@claritylabs/cl-sdk 1.3.8 → 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 +13 -10
- package/dist/index.d.mts +2810 -440
- package/dist/index.d.ts +2810 -440
- package/dist/index.js +1751 -249
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1735 -249
- package/dist/index.mjs.map +1 -1
- package/dist/storage-sqlite.d.mts +964 -160
- package/dist/storage-sqlite.d.ts +964 -160
- 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 +2 -2
package/dist/index.mjs
CHANGED
|
@@ -567,14 +567,20 @@ var FormReferenceSchema = z3.object({
|
|
|
567
567
|
title: z3.string().optional(),
|
|
568
568
|
formType: z3.enum(["coverage", "endorsement", "declarations", "application", "notice", "other"]),
|
|
569
569
|
pageStart: z3.number().optional(),
|
|
570
|
-
pageEnd: z3.number().optional()
|
|
570
|
+
pageEnd: z3.number().optional(),
|
|
571
|
+
documentNodeId: z3.string().optional(),
|
|
572
|
+
sourceSpanIds: z3.array(z3.string()).optional(),
|
|
573
|
+
sourceTextHash: z3.string().optional()
|
|
571
574
|
});
|
|
572
575
|
var TaxFeeItemSchema = z3.object({
|
|
573
576
|
name: z3.string(),
|
|
574
577
|
amount: z3.string(),
|
|
575
578
|
amountValue: z3.number().optional(),
|
|
576
579
|
type: z3.enum(["tax", "fee", "surcharge", "assessment"]).optional(),
|
|
577
|
-
description: z3.string().optional()
|
|
580
|
+
description: z3.string().optional(),
|
|
581
|
+
documentNodeId: z3.string().optional(),
|
|
582
|
+
sourceSpanIds: z3.array(z3.string()).optional(),
|
|
583
|
+
sourceTextHash: z3.string().optional()
|
|
578
584
|
});
|
|
579
585
|
var RatingBasisSchema = z3.object({
|
|
580
586
|
type: RatingBasisTypeSchema,
|
|
@@ -630,6 +636,7 @@ var CoverageSchema = z4.object({
|
|
|
630
636
|
sectionRef: z4.string().optional(),
|
|
631
637
|
originalContent: z4.string().optional(),
|
|
632
638
|
recordId: z4.string().optional(),
|
|
639
|
+
documentNodeId: z4.string().optional(),
|
|
633
640
|
sourceSpanIds: z4.array(z4.string()).optional(),
|
|
634
641
|
sourceTextHash: z4.string().optional()
|
|
635
642
|
});
|
|
@@ -659,6 +666,7 @@ var EnrichedCoverageSchema = z4.object({
|
|
|
659
666
|
sectionRef: z4.string().optional(),
|
|
660
667
|
originalContent: z4.string().optional(),
|
|
661
668
|
recordId: z4.string().optional(),
|
|
669
|
+
documentNodeId: z4.string().optional(),
|
|
662
670
|
sourceSpanIds: z4.array(z4.string()).optional(),
|
|
663
671
|
sourceTextHash: z4.string().optional()
|
|
664
672
|
});
|
|
@@ -687,6 +695,7 @@ var EndorsementSchema = z5.object({
|
|
|
687
695
|
pageStart: z5.number(),
|
|
688
696
|
pageEnd: z5.number().optional(),
|
|
689
697
|
recordId: z5.string().optional(),
|
|
698
|
+
documentNodeId: z5.string().optional(),
|
|
690
699
|
sourceSpanIds: z5.array(z5.string()).optional(),
|
|
691
700
|
sourceTextHash: z5.string().optional()
|
|
692
701
|
});
|
|
@@ -705,6 +714,7 @@ var ExclusionSchema = z6.object({
|
|
|
705
714
|
content: z6.string(),
|
|
706
715
|
pageNumber: z6.number().optional(),
|
|
707
716
|
recordId: z6.string().optional(),
|
|
717
|
+
documentNodeId: z6.string().optional(),
|
|
708
718
|
sourceSpanIds: z6.array(z6.string()).optional(),
|
|
709
719
|
sourceTextHash: z6.string().optional()
|
|
710
720
|
});
|
|
@@ -722,6 +732,7 @@ var PolicyConditionSchema = z7.object({
|
|
|
722
732
|
keyValues: z7.array(ConditionKeyValueSchema).optional(),
|
|
723
733
|
pageNumber: z7.number().optional(),
|
|
724
734
|
recordId: z7.string().optional(),
|
|
735
|
+
documentNodeId: z7.string().optional(),
|
|
725
736
|
sourceSpanIds: z7.array(z7.string()).optional(),
|
|
726
737
|
sourceTextHash: z7.string().optional()
|
|
727
738
|
});
|
|
@@ -1298,6 +1309,7 @@ var SubsectionSchema = z16.object({
|
|
|
1298
1309
|
pageNumber: z16.number().optional(),
|
|
1299
1310
|
excerpt: z16.string().optional(),
|
|
1300
1311
|
content: z16.string().optional(),
|
|
1312
|
+
documentNodeId: z16.string().optional(),
|
|
1301
1313
|
sourceSpanIds: z16.array(z16.string()).optional(),
|
|
1302
1314
|
sourceTextHash: z16.string().optional()
|
|
1303
1315
|
});
|
|
@@ -1312,6 +1324,7 @@ var SectionSchema = z16.object({
|
|
|
1312
1324
|
content: z16.string().optional(),
|
|
1313
1325
|
subsections: z16.array(SubsectionSchema).optional(),
|
|
1314
1326
|
recordId: z16.string().optional(),
|
|
1327
|
+
documentNodeId: z16.string().optional(),
|
|
1315
1328
|
sourceSpanIds: z16.array(z16.string()).optional(),
|
|
1316
1329
|
sourceTextHash: z16.string().optional()
|
|
1317
1330
|
});
|
|
@@ -1325,13 +1338,19 @@ var UnderwritingConditionSchema = z16.object({
|
|
|
1325
1338
|
var PremiumLineSchema = z16.object({
|
|
1326
1339
|
line: z16.string(),
|
|
1327
1340
|
amount: z16.string(),
|
|
1328
|
-
amountValue: z16.number().optional()
|
|
1341
|
+
amountValue: z16.number().optional(),
|
|
1342
|
+
documentNodeId: z16.string().optional(),
|
|
1343
|
+
sourceSpanIds: z16.array(z16.string()).optional(),
|
|
1344
|
+
sourceTextHash: z16.string().optional()
|
|
1329
1345
|
});
|
|
1330
1346
|
var AuxiliaryFactSchema = z16.object({
|
|
1331
1347
|
key: z16.string(),
|
|
1332
1348
|
value: z16.string(),
|
|
1333
1349
|
subject: z16.string().optional(),
|
|
1334
|
-
context: z16.string().optional()
|
|
1350
|
+
context: z16.string().optional(),
|
|
1351
|
+
documentNodeId: z16.string().optional(),
|
|
1352
|
+
sourceSpanIds: z16.array(z16.string()).optional(),
|
|
1353
|
+
sourceTextHash: z16.string().optional()
|
|
1335
1354
|
});
|
|
1336
1355
|
var DefinitionSchema = z16.object({
|
|
1337
1356
|
term: z16.string(),
|
|
@@ -1342,6 +1361,7 @@ var DefinitionSchema = z16.object({
|
|
|
1342
1361
|
sectionRef: z16.string().optional(),
|
|
1343
1362
|
originalContent: z16.string().optional(),
|
|
1344
1363
|
recordId: z16.string().optional(),
|
|
1364
|
+
documentNodeId: z16.string().optional(),
|
|
1345
1365
|
sourceSpanIds: z16.array(z16.string()).optional(),
|
|
1346
1366
|
sourceTextHash: z16.string().optional()
|
|
1347
1367
|
});
|
|
@@ -1359,9 +1379,62 @@ var CoveredReasonSchema = z16.object({
|
|
|
1359
1379
|
sectionRef: z16.string().optional(),
|
|
1360
1380
|
originalContent: z16.string().optional(),
|
|
1361
1381
|
recordId: z16.string().optional(),
|
|
1382
|
+
documentNodeId: z16.string().optional(),
|
|
1362
1383
|
sourceSpanIds: z16.array(z16.string()).optional(),
|
|
1363
1384
|
sourceTextHash: z16.string().optional()
|
|
1364
1385
|
});
|
|
1386
|
+
var DocumentTableOfContentsEntrySchema = z16.object({
|
|
1387
|
+
title: z16.string(),
|
|
1388
|
+
level: z16.number().int().positive().optional(),
|
|
1389
|
+
pageStart: z16.number().optional(),
|
|
1390
|
+
pageEnd: z16.number().optional(),
|
|
1391
|
+
documentNodeId: z16.string().optional(),
|
|
1392
|
+
sourceSpanIds: z16.array(z16.string()).optional()
|
|
1393
|
+
});
|
|
1394
|
+
var DocumentPageMapEntrySchema = z16.object({
|
|
1395
|
+
page: z16.number().int().positive(),
|
|
1396
|
+
label: z16.string().optional(),
|
|
1397
|
+
formNumber: z16.string().optional(),
|
|
1398
|
+
formTitle: z16.string().optional(),
|
|
1399
|
+
sectionTitle: z16.string().optional(),
|
|
1400
|
+
extractorNames: z16.array(z16.string()).optional(),
|
|
1401
|
+
sourceSpanIds: z16.array(z16.string()).optional()
|
|
1402
|
+
});
|
|
1403
|
+
var DocumentAgentGuidanceSchema = z16.object({
|
|
1404
|
+
kind: z16.string(),
|
|
1405
|
+
title: z16.string(),
|
|
1406
|
+
detail: z16.string(),
|
|
1407
|
+
sourceSpanIds: z16.array(z16.string()).optional()
|
|
1408
|
+
});
|
|
1409
|
+
var DocumentMetadataSchema = z16.object({
|
|
1410
|
+
sourceTreeVersion: z16.string().optional(),
|
|
1411
|
+
sourceTreeCanonical: z16.boolean().optional(),
|
|
1412
|
+
formInventory: z16.array(FormReferenceSchema).optional(),
|
|
1413
|
+
tableOfContents: z16.array(DocumentTableOfContentsEntrySchema).optional(),
|
|
1414
|
+
pageMap: z16.array(DocumentPageMapEntrySchema).optional(),
|
|
1415
|
+
agentGuidance: z16.array(DocumentAgentGuidanceSchema).optional()
|
|
1416
|
+
});
|
|
1417
|
+
var DocumentNodeSchema = z16.lazy(
|
|
1418
|
+
() => z16.object({
|
|
1419
|
+
id: z16.string(),
|
|
1420
|
+
title: z16.string(),
|
|
1421
|
+
originalTitle: z16.string().optional(),
|
|
1422
|
+
type: z16.string().optional(),
|
|
1423
|
+
label: z16.string().optional(),
|
|
1424
|
+
level: z16.number().int().positive().optional(),
|
|
1425
|
+
sectionNumber: z16.string().optional(),
|
|
1426
|
+
pageStart: z16.number().optional(),
|
|
1427
|
+
pageEnd: z16.number().optional(),
|
|
1428
|
+
formNumber: z16.string().optional(),
|
|
1429
|
+
formTitle: z16.string().optional(),
|
|
1430
|
+
excerpt: z16.string().optional(),
|
|
1431
|
+
content: z16.string().optional(),
|
|
1432
|
+
interpretationLabels: z16.array(z16.string()).optional(),
|
|
1433
|
+
sourceSpanIds: z16.array(z16.string()).optional(),
|
|
1434
|
+
sourceTextHash: z16.string().optional(),
|
|
1435
|
+
children: z16.array(DocumentNodeSchema).optional()
|
|
1436
|
+
})
|
|
1437
|
+
);
|
|
1365
1438
|
var BaseDocumentFields = {
|
|
1366
1439
|
id: z16.string(),
|
|
1367
1440
|
carrier: z16.string(),
|
|
@@ -1372,6 +1445,8 @@ var BaseDocumentFields = {
|
|
|
1372
1445
|
summary: z16.string().optional(),
|
|
1373
1446
|
policyTypes: z16.array(z16.string()).optional(),
|
|
1374
1447
|
coverages: z16.array(CoverageSchema),
|
|
1448
|
+
documentMetadata: DocumentMetadataSchema,
|
|
1449
|
+
documentOutline: z16.array(DocumentNodeSchema),
|
|
1375
1450
|
sections: z16.array(SectionSchema).optional(),
|
|
1376
1451
|
definitions: z16.array(DefinitionSchema).optional(),
|
|
1377
1452
|
coveredReasons: z16.array(CoveredReasonSchema).optional(),
|
|
@@ -1933,6 +2008,86 @@ var SourceChunkSchema = z20.object({
|
|
|
1933
2008
|
pageEnd: z20.number().int().positive().optional(),
|
|
1934
2009
|
metadata: z20.record(z20.string(), z20.string()).default({})
|
|
1935
2010
|
});
|
|
2011
|
+
var DocumentSourceNodeKindSchema = z20.enum([
|
|
2012
|
+
"document",
|
|
2013
|
+
"page_group",
|
|
2014
|
+
"page",
|
|
2015
|
+
"form",
|
|
2016
|
+
"endorsement",
|
|
2017
|
+
"section",
|
|
2018
|
+
"schedule",
|
|
2019
|
+
"clause",
|
|
2020
|
+
"table",
|
|
2021
|
+
"table_row",
|
|
2022
|
+
"table_cell",
|
|
2023
|
+
"text"
|
|
2024
|
+
]);
|
|
2025
|
+
var DocumentSourceNodeSchema = z20.object({
|
|
2026
|
+
id: z20.string().min(1),
|
|
2027
|
+
documentId: z20.string().min(1),
|
|
2028
|
+
parentId: z20.string().optional(),
|
|
2029
|
+
kind: DocumentSourceNodeKindSchema,
|
|
2030
|
+
title: z20.string(),
|
|
2031
|
+
description: z20.string(),
|
|
2032
|
+
textExcerpt: z20.string().optional(),
|
|
2033
|
+
sourceSpanIds: z20.array(z20.string().min(1)),
|
|
2034
|
+
pageStart: z20.number().int().positive().optional(),
|
|
2035
|
+
pageEnd: z20.number().int().positive().optional(),
|
|
2036
|
+
bbox: z20.array(SourceSpanBBoxSchema).optional(),
|
|
2037
|
+
order: z20.number().int().nonnegative(),
|
|
2038
|
+
path: z20.string(),
|
|
2039
|
+
metadata: z20.record(z20.string(), z20.unknown()).optional()
|
|
2040
|
+
});
|
|
2041
|
+
var SourceBackedValueSchema = z20.object({
|
|
2042
|
+
value: z20.string(),
|
|
2043
|
+
normalizedValue: z20.string().optional(),
|
|
2044
|
+
confidence: z20.enum(["low", "medium", "high"]).default("medium"),
|
|
2045
|
+
sourceNodeIds: z20.array(z20.string().min(1)).default([]),
|
|
2046
|
+
sourceSpanIds: z20.array(z20.string().min(1)).default([])
|
|
2047
|
+
});
|
|
2048
|
+
var OperationalCoverageLineSchema = z20.object({
|
|
2049
|
+
name: z20.string(),
|
|
2050
|
+
coverageCode: z20.string().optional(),
|
|
2051
|
+
limit: z20.string().optional(),
|
|
2052
|
+
deductible: z20.string().optional(),
|
|
2053
|
+
premium: z20.string().optional(),
|
|
2054
|
+
formNumber: z20.string().optional(),
|
|
2055
|
+
sectionRef: z20.string().optional(),
|
|
2056
|
+
sourceNodeIds: z20.array(z20.string().min(1)).default([]),
|
|
2057
|
+
sourceSpanIds: z20.array(z20.string().min(1)).default([])
|
|
2058
|
+
});
|
|
2059
|
+
var OperationalPartySchema = z20.object({
|
|
2060
|
+
role: z20.string(),
|
|
2061
|
+
name: z20.string(),
|
|
2062
|
+
sourceNodeIds: z20.array(z20.string().min(1)).default([]),
|
|
2063
|
+
sourceSpanIds: z20.array(z20.string().min(1)).default([])
|
|
2064
|
+
});
|
|
2065
|
+
var OperationalEndorsementSupportSchema = z20.object({
|
|
2066
|
+
kind: z20.string(),
|
|
2067
|
+
status: z20.enum(["supported", "excluded", "requires_review"]),
|
|
2068
|
+
summary: z20.string(),
|
|
2069
|
+
sourceNodeIds: z20.array(z20.string().min(1)).default([]),
|
|
2070
|
+
sourceSpanIds: z20.array(z20.string().min(1)).default([])
|
|
2071
|
+
});
|
|
2072
|
+
var PolicyOperationalProfileSchema = z20.object({
|
|
2073
|
+
documentType: z20.enum(["policy", "quote"]).default("policy"),
|
|
2074
|
+
policyTypes: z20.array(z20.string()).default(["other"]),
|
|
2075
|
+
policyNumber: SourceBackedValueSchema.optional(),
|
|
2076
|
+
namedInsured: SourceBackedValueSchema.optional(),
|
|
2077
|
+
insurer: SourceBackedValueSchema.optional(),
|
|
2078
|
+
broker: SourceBackedValueSchema.optional(),
|
|
2079
|
+
effectiveDate: SourceBackedValueSchema.optional(),
|
|
2080
|
+
expirationDate: SourceBackedValueSchema.optional(),
|
|
2081
|
+
retroactiveDate: SourceBackedValueSchema.optional(),
|
|
2082
|
+
premium: SourceBackedValueSchema.optional(),
|
|
2083
|
+
coverageTypes: z20.array(z20.string()).default([]),
|
|
2084
|
+
coverages: z20.array(OperationalCoverageLineSchema).default([]),
|
|
2085
|
+
parties: z20.array(OperationalPartySchema).default([]),
|
|
2086
|
+
endorsementSupport: z20.array(OperationalEndorsementSupportSchema).default([]),
|
|
2087
|
+
sourceNodeIds: z20.array(z20.string().min(1)).default([]),
|
|
2088
|
+
sourceSpanIds: z20.array(z20.string().min(1)).default([]),
|
|
2089
|
+
warnings: z20.array(z20.string()).default([])
|
|
2090
|
+
});
|
|
1936
2091
|
|
|
1937
2092
|
// src/source/ids.ts
|
|
1938
2093
|
function normalizeText(text) {
|
|
@@ -2116,8 +2271,8 @@ function chunkSourceSpans(spans, options = {}) {
|
|
|
2116
2271
|
if (current.length === 0) return;
|
|
2117
2272
|
const text = current.map((span) => span.text).join("\n\n");
|
|
2118
2273
|
const textHash = sourceSpanTextHash(text);
|
|
2119
|
-
const
|
|
2120
|
-
const
|
|
2274
|
+
const pageStart2 = firstNumber(current.map((span) => span.pageStart));
|
|
2275
|
+
const pageEnd2 = lastNumber(current.map((span) => span.pageEnd ?? span.pageStart));
|
|
2121
2276
|
const chunk = {
|
|
2122
2277
|
id: `${sanitizeIdPart(current[0].documentId)}:source_chunk:${chunks.length}:${stableHash2({
|
|
2123
2278
|
sourceSpanIds: current.map((span) => span.id),
|
|
@@ -2127,8 +2282,8 @@ function chunkSourceSpans(spans, options = {}) {
|
|
|
2127
2282
|
sourceSpanIds: current.map((span) => span.id),
|
|
2128
2283
|
text,
|
|
2129
2284
|
textHash,
|
|
2130
|
-
pageStart,
|
|
2131
|
-
pageEnd,
|
|
2285
|
+
pageStart: pageStart2,
|
|
2286
|
+
pageEnd: pageEnd2,
|
|
2132
2287
|
metadata: mergeMetadata(current)
|
|
2133
2288
|
};
|
|
2134
2289
|
chunks.push(SourceChunkSchema.parse(chunk));
|
|
@@ -2281,6 +2436,542 @@ function matchesFilters(span, filters) {
|
|
|
2281
2436
|
return true;
|
|
2282
2437
|
}
|
|
2283
2438
|
|
|
2439
|
+
// src/source/tree.ts
|
|
2440
|
+
function normalizeWhitespace2(value) {
|
|
2441
|
+
return value.replace(/\s+/g, " ").trim();
|
|
2442
|
+
}
|
|
2443
|
+
function sanitizeIdPart2(value) {
|
|
2444
|
+
return value.replace(/[^a-zA-Z0-9_.:-]/g, "_");
|
|
2445
|
+
}
|
|
2446
|
+
function truncate(value, maxChars) {
|
|
2447
|
+
const text = normalizeWhitespace2(value);
|
|
2448
|
+
return text.length > maxChars ? `${text.slice(0, maxChars).trimEnd()}...` : text;
|
|
2449
|
+
}
|
|
2450
|
+
function pageStart(span) {
|
|
2451
|
+
return span.pageStart ?? span.location?.page ?? span.location?.startPage;
|
|
2452
|
+
}
|
|
2453
|
+
function pageEnd(span) {
|
|
2454
|
+
return span.pageEnd ?? span.location?.endPage ?? pageStart(span);
|
|
2455
|
+
}
|
|
2456
|
+
function sourceUnit2(span) {
|
|
2457
|
+
return span.sourceUnit ?? span.metadata?.sourceUnit ?? span.metadata?.elementType;
|
|
2458
|
+
}
|
|
2459
|
+
function elementType(span) {
|
|
2460
|
+
return span.metadata?.elementType ?? span.metadata?.sourceUnit ?? span.sourceUnit;
|
|
2461
|
+
}
|
|
2462
|
+
function tableId(span) {
|
|
2463
|
+
return span.table?.tableId ?? span.metadata?.tableId;
|
|
2464
|
+
}
|
|
2465
|
+
function rowSpanId(span) {
|
|
2466
|
+
return span.parentSpanId ?? span.table?.rowSpanId ?? span.metadata?.rowSpanId;
|
|
2467
|
+
}
|
|
2468
|
+
function nodeId(documentId, kind, parts) {
|
|
2469
|
+
return [
|
|
2470
|
+
sanitizeIdPart2(documentId),
|
|
2471
|
+
"source_node",
|
|
2472
|
+
kind,
|
|
2473
|
+
stableHash2(parts.filter((part) => part !== void 0).join("|")).slice(0, 12)
|
|
2474
|
+
].join(":");
|
|
2475
|
+
}
|
|
2476
|
+
function titleCase(value) {
|
|
2477
|
+
return value.replace(/[_-]+/g, " ").replace(/\b\w/g, (char) => char.toUpperCase()).trim();
|
|
2478
|
+
}
|
|
2479
|
+
function nodeTextDescription(params) {
|
|
2480
|
+
return [
|
|
2481
|
+
params.title,
|
|
2482
|
+
params.kind.replace(/_/g, " "),
|
|
2483
|
+
params.page ? `page ${params.page}` : void 0,
|
|
2484
|
+
params.formNumber ? `form ${params.formNumber}` : void 0,
|
|
2485
|
+
params.text ? truncate(params.text, 1200) : void 0
|
|
2486
|
+
].filter(Boolean).join(" | ");
|
|
2487
|
+
}
|
|
2488
|
+
function normalizeNodeKind(span) {
|
|
2489
|
+
const unit = sourceUnit2(span);
|
|
2490
|
+
const element = elementType(span);
|
|
2491
|
+
if (unit === "page") return "page";
|
|
2492
|
+
if (unit === "table") return "table";
|
|
2493
|
+
if (unit === "table_row") return "table_row";
|
|
2494
|
+
if (unit === "table_cell") return "table_cell";
|
|
2495
|
+
if (unit === "key_value") return "schedule";
|
|
2496
|
+
if (unit === "section") return "section";
|
|
2497
|
+
if (element === "title" || element === "section_candidate") {
|
|
2498
|
+
const text = span.text.toLowerCase();
|
|
2499
|
+
if (/endorsement/.test(text)) return "endorsement";
|
|
2500
|
+
if (/schedule|declarations?/.test(text)) return "schedule";
|
|
2501
|
+
if (/clause|condition|exclusion|definition/.test(text)) return "clause";
|
|
2502
|
+
return "section";
|
|
2503
|
+
}
|
|
2504
|
+
return "text";
|
|
2505
|
+
}
|
|
2506
|
+
function pageNodeTitle(page) {
|
|
2507
|
+
return `Page ${page}`;
|
|
2508
|
+
}
|
|
2509
|
+
function makeNode(params) {
|
|
2510
|
+
return {
|
|
2511
|
+
id: params.id,
|
|
2512
|
+
documentId: params.documentId,
|
|
2513
|
+
parentId: params.parentId,
|
|
2514
|
+
kind: params.kind,
|
|
2515
|
+
title: params.title,
|
|
2516
|
+
description: params.description ?? nodeTextDescription({
|
|
2517
|
+
kind: params.kind,
|
|
2518
|
+
title: params.title,
|
|
2519
|
+
text: params.textExcerpt,
|
|
2520
|
+
page: params.pageStart,
|
|
2521
|
+
formNumber: typeof params.metadata?.formNumber === "string" ? params.metadata.formNumber : void 0
|
|
2522
|
+
}),
|
|
2523
|
+
textExcerpt: params.textExcerpt,
|
|
2524
|
+
sourceSpanIds: params.sourceSpanIds ?? [],
|
|
2525
|
+
pageStart: params.pageStart,
|
|
2526
|
+
pageEnd: params.pageEnd,
|
|
2527
|
+
bbox: params.bbox,
|
|
2528
|
+
order: params.order,
|
|
2529
|
+
path: "",
|
|
2530
|
+
metadata: params.metadata
|
|
2531
|
+
};
|
|
2532
|
+
}
|
|
2533
|
+
function sortSpans(left, right) {
|
|
2534
|
+
const leftPage = pageStart(left) ?? 0;
|
|
2535
|
+
const rightPage = pageStart(right) ?? 0;
|
|
2536
|
+
if (leftPage !== rightPage) return leftPage - rightPage;
|
|
2537
|
+
const leftRow = left.table?.rowIndex ?? Number(left.metadata?.rowIndex ?? 0);
|
|
2538
|
+
const rightRow = right.table?.rowIndex ?? Number(right.metadata?.rowIndex ?? 0);
|
|
2539
|
+
if (leftRow !== rightRow) return leftRow - rightRow;
|
|
2540
|
+
const leftCol = left.table?.columnIndex ?? Number(left.metadata?.columnIndex ?? 0);
|
|
2541
|
+
const rightCol = right.table?.columnIndex ?? Number(right.metadata?.columnIndex ?? 0);
|
|
2542
|
+
if (leftCol !== rightCol) return leftCol - rightCol;
|
|
2543
|
+
return left.id.localeCompare(right.id);
|
|
2544
|
+
}
|
|
2545
|
+
function normalizeDocumentSourceTreePaths(nodes) {
|
|
2546
|
+
const byParent = /* @__PURE__ */ new Map();
|
|
2547
|
+
for (const node of nodes) {
|
|
2548
|
+
const key = node.parentId;
|
|
2549
|
+
const group = byParent.get(key) ?? [];
|
|
2550
|
+
group.push(node);
|
|
2551
|
+
byParent.set(key, group);
|
|
2552
|
+
}
|
|
2553
|
+
for (const group of byParent.values()) {
|
|
2554
|
+
group.sort((left, right) => left.order - right.order || left.id.localeCompare(right.id));
|
|
2555
|
+
}
|
|
2556
|
+
const result = [];
|
|
2557
|
+
const visit = (node, path) => {
|
|
2558
|
+
const next = { ...node, path };
|
|
2559
|
+
result.push(next);
|
|
2560
|
+
const children = byParent.get(node.id) ?? [];
|
|
2561
|
+
children.forEach((child, index) => visit(child, `${path}.${index + 1}`));
|
|
2562
|
+
};
|
|
2563
|
+
const roots = byParent.get(void 0) ?? [];
|
|
2564
|
+
roots.forEach((root, index) => visit(root, String(index + 1)));
|
|
2565
|
+
return result;
|
|
2566
|
+
}
|
|
2567
|
+
function buildDocumentSourceTree(sourceSpans, documentId) {
|
|
2568
|
+
const orderedSpans = [...sourceSpans].sort(sortSpans);
|
|
2569
|
+
const resolvedDocumentId = documentId ?? orderedSpans[0]?.documentId ?? "document";
|
|
2570
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
2571
|
+
let order = 0;
|
|
2572
|
+
const rootId = nodeId(resolvedDocumentId, "document", [resolvedDocumentId]);
|
|
2573
|
+
nodes.set(rootId, makeNode({
|
|
2574
|
+
id: rootId,
|
|
2575
|
+
documentId: resolvedDocumentId,
|
|
2576
|
+
kind: "document",
|
|
2577
|
+
title: "Document",
|
|
2578
|
+
description: "Document root for source-native policy hierarchy",
|
|
2579
|
+
sourceSpanIds: orderedSpans.map((span) => span.id).slice(0, 200),
|
|
2580
|
+
pageStart: orderedSpans.map(pageStart).find((value) => typeof value === "number"),
|
|
2581
|
+
pageEnd: [...orderedSpans].reverse().map(pageEnd).find((value) => typeof value === "number"),
|
|
2582
|
+
order: order++,
|
|
2583
|
+
metadata: { sourceTreeVersion: "v3" }
|
|
2584
|
+
}));
|
|
2585
|
+
const pageNodeIds = /* @__PURE__ */ new Map();
|
|
2586
|
+
const tableNodeIds = /* @__PURE__ */ new Map();
|
|
2587
|
+
const rowNodeIds = /* @__PURE__ */ new Map();
|
|
2588
|
+
const ensurePage = (page) => {
|
|
2589
|
+
const existing = pageNodeIds.get(page);
|
|
2590
|
+
if (existing) return existing;
|
|
2591
|
+
const id = nodeId(resolvedDocumentId, "page", [page]);
|
|
2592
|
+
const pageSpan = orderedSpans.find((span) => pageStart(span) === page && sourceUnit2(span) === "page");
|
|
2593
|
+
nodes.set(id, makeNode({
|
|
2594
|
+
id,
|
|
2595
|
+
documentId: resolvedDocumentId,
|
|
2596
|
+
parentId: rootId,
|
|
2597
|
+
kind: "page",
|
|
2598
|
+
title: pageNodeTitle(page),
|
|
2599
|
+
description: pageSpan ? nodeTextDescription({ kind: "page", title: pageNodeTitle(page), text: pageSpan.text, page }) : pageNodeTitle(page),
|
|
2600
|
+
textExcerpt: pageSpan ? truncate(pageSpan.text, 1600) : void 0,
|
|
2601
|
+
sourceSpanIds: pageSpan ? [pageSpan.id] : [],
|
|
2602
|
+
pageStart: page,
|
|
2603
|
+
pageEnd: page,
|
|
2604
|
+
bbox: pageSpan?.bbox,
|
|
2605
|
+
order: order++,
|
|
2606
|
+
metadata: { sourceUnit: "page" }
|
|
2607
|
+
}));
|
|
2608
|
+
pageNodeIds.set(page, id);
|
|
2609
|
+
return id;
|
|
2610
|
+
};
|
|
2611
|
+
const ensureTable = (span, pageParentId) => {
|
|
2612
|
+
const idSource = tableId(span) ?? `${span.documentId}:p${pageStart(span) ?? "na"}:table:${nodes.size}`;
|
|
2613
|
+
const existing = tableNodeIds.get(idSource);
|
|
2614
|
+
if (existing) return existing;
|
|
2615
|
+
const id = nodeId(resolvedDocumentId, "table", [idSource]);
|
|
2616
|
+
nodes.set(id, makeNode({
|
|
2617
|
+
id,
|
|
2618
|
+
documentId: resolvedDocumentId,
|
|
2619
|
+
parentId: pageParentId,
|
|
2620
|
+
kind: "table",
|
|
2621
|
+
title: `Table ${tableNodeIds.size + 1}`,
|
|
2622
|
+
description: `Table on page ${pageStart(span) ?? "unknown"} for source rows and cells`,
|
|
2623
|
+
sourceSpanIds: [],
|
|
2624
|
+
pageStart: pageStart(span),
|
|
2625
|
+
pageEnd: pageEnd(span),
|
|
2626
|
+
order: order++,
|
|
2627
|
+
metadata: { tableId: idSource, sourceUnit: "table" }
|
|
2628
|
+
}));
|
|
2629
|
+
tableNodeIds.set(idSource, id);
|
|
2630
|
+
return id;
|
|
2631
|
+
};
|
|
2632
|
+
const addStandaloneSpanNode = (span, parentId) => {
|
|
2633
|
+
const kind = normalizeNodeKind(span);
|
|
2634
|
+
if (kind === "page") return;
|
|
2635
|
+
const page = pageStart(span);
|
|
2636
|
+
const title = span.sectionId ?? span.formNumber ?? (kind === "table_cell" && span.table?.columnName ? String(span.table.columnName) : void 0) ?? titleCase(kind);
|
|
2637
|
+
const id = nodeId(resolvedDocumentId, kind, [span.id]);
|
|
2638
|
+
nodes.set(id, makeNode({
|
|
2639
|
+
id,
|
|
2640
|
+
documentId: resolvedDocumentId,
|
|
2641
|
+
parentId,
|
|
2642
|
+
kind,
|
|
2643
|
+
title,
|
|
2644
|
+
description: nodeTextDescription({ kind, title, text: span.text, page, formNumber: span.formNumber }),
|
|
2645
|
+
textExcerpt: truncate(span.text, 1600),
|
|
2646
|
+
sourceSpanIds: [span.id],
|
|
2647
|
+
pageStart: page,
|
|
2648
|
+
pageEnd: pageEnd(span),
|
|
2649
|
+
bbox: span.bbox,
|
|
2650
|
+
order: order++,
|
|
2651
|
+
metadata: {
|
|
2652
|
+
...span.metadata ?? {},
|
|
2653
|
+
formNumber: span.formNumber,
|
|
2654
|
+
sourceUnit: sourceUnit2(span)
|
|
2655
|
+
}
|
|
2656
|
+
}));
|
|
2657
|
+
};
|
|
2658
|
+
for (const span of orderedSpans) {
|
|
2659
|
+
const page = pageStart(span);
|
|
2660
|
+
const pageParentId = page ? ensurePage(page) : rootId;
|
|
2661
|
+
const kind = normalizeNodeKind(span);
|
|
2662
|
+
if (kind === "page") continue;
|
|
2663
|
+
if (kind === "table_row") {
|
|
2664
|
+
const tableParentId = ensureTable(span, pageParentId);
|
|
2665
|
+
const rowKey = span.id;
|
|
2666
|
+
const id = nodeId(resolvedDocumentId, "table_row", [span.id]);
|
|
2667
|
+
nodes.set(id, makeNode({
|
|
2668
|
+
id,
|
|
2669
|
+
documentId: resolvedDocumentId,
|
|
2670
|
+
parentId: tableParentId,
|
|
2671
|
+
kind,
|
|
2672
|
+
title: span.table?.isHeader ? "Header row" : `Row ${(span.table?.rowIndex ?? 0) + 1}`,
|
|
2673
|
+
description: nodeTextDescription({ kind, title: "Table row", text: span.text, page }),
|
|
2674
|
+
textExcerpt: truncate(span.text, 1600),
|
|
2675
|
+
sourceSpanIds: [span.id],
|
|
2676
|
+
pageStart: page,
|
|
2677
|
+
pageEnd: pageEnd(span),
|
|
2678
|
+
bbox: span.bbox,
|
|
2679
|
+
order: order++,
|
|
2680
|
+
metadata: {
|
|
2681
|
+
...span.metadata ?? {},
|
|
2682
|
+
...span.table ?? {},
|
|
2683
|
+
sourceUnit: "table_row"
|
|
2684
|
+
}
|
|
2685
|
+
}));
|
|
2686
|
+
rowNodeIds.set(rowKey, id);
|
|
2687
|
+
continue;
|
|
2688
|
+
}
|
|
2689
|
+
if (kind === "table_cell") {
|
|
2690
|
+
const tableParentId = ensureTable(span, pageParentId);
|
|
2691
|
+
const parentRowId2 = rowSpanId(span);
|
|
2692
|
+
const parentId = parentRowId2 ? rowNodeIds.get(parentRowId2) ?? tableParentId : tableParentId;
|
|
2693
|
+
addStandaloneSpanNode(span, parentId);
|
|
2694
|
+
continue;
|
|
2695
|
+
}
|
|
2696
|
+
addStandaloneSpanNode(span, pageParentId);
|
|
2697
|
+
}
|
|
2698
|
+
return normalizeDocumentSourceTreePaths([...nodes.values()]);
|
|
2699
|
+
}
|
|
2700
|
+
|
|
2701
|
+
// src/source/operational-profile.ts
|
|
2702
|
+
function normalizeWhitespace3(value) {
|
|
2703
|
+
return value.replace(/\s+/g, " ").trim();
|
|
2704
|
+
}
|
|
2705
|
+
function cleanValue(value) {
|
|
2706
|
+
if (!value) return void 0;
|
|
2707
|
+
return normalizeWhitespace3(value.replace(/^[\s:;#-]+|[\s;,.]+$/g, ""));
|
|
2708
|
+
}
|
|
2709
|
+
function moneyValue(value) {
|
|
2710
|
+
const clean = cleanValue(value);
|
|
2711
|
+
if (!clean) return void 0;
|
|
2712
|
+
if (/^\$/.test(clean)) return clean;
|
|
2713
|
+
if (/^\d{1,3}(?:,\d{3})*(?:\.\d{2})?$/.test(clean)) return `$${clean}`;
|
|
2714
|
+
return clean;
|
|
2715
|
+
}
|
|
2716
|
+
function nodeText(node) {
|
|
2717
|
+
return normalizeWhitespace3([
|
|
2718
|
+
node.title,
|
|
2719
|
+
node.description,
|
|
2720
|
+
node.textExcerpt
|
|
2721
|
+
].filter(Boolean).join(" "));
|
|
2722
|
+
}
|
|
2723
|
+
function valueFromNode(node, value, confidence = "medium") {
|
|
2724
|
+
return {
|
|
2725
|
+
value,
|
|
2726
|
+
confidence,
|
|
2727
|
+
sourceNodeIds: [node.id],
|
|
2728
|
+
sourceSpanIds: node.sourceSpanIds
|
|
2729
|
+
};
|
|
2730
|
+
}
|
|
2731
|
+
function firstMatch(nodes, patterns) {
|
|
2732
|
+
for (const node of nodes) {
|
|
2733
|
+
const text = nodeText(node);
|
|
2734
|
+
for (const pattern of patterns) {
|
|
2735
|
+
const match = text.match(pattern);
|
|
2736
|
+
const value = cleanValue(match?.[1]);
|
|
2737
|
+
if (value) return valueFromNode(node, value, "high");
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
return void 0;
|
|
2741
|
+
}
|
|
2742
|
+
function inferPolicyTypes(nodes) {
|
|
2743
|
+
const text = nodes.slice(0, 40).map(nodeText).join(" ").toLowerCase();
|
|
2744
|
+
const types = [];
|
|
2745
|
+
const add = (pattern, type) => {
|
|
2746
|
+
if (pattern.test(text) && !types.includes(type)) types.push(type);
|
|
2747
|
+
};
|
|
2748
|
+
add(/\b(cyber|network security|privacy liability|data breach)\b/i, "cyber");
|
|
2749
|
+
add(/\b(professional liability|errors?\s*&?\s*omissions|e&o)\b/i, "professional_liability");
|
|
2750
|
+
add(/\b(commercial general liability|general liability|cgl)\b/i, "general_liability");
|
|
2751
|
+
add(/\b(umbrella|excess liability)\b/i, "umbrella");
|
|
2752
|
+
add(/\b(workers'? compensation|employers'? liability)\b/i, "workers_comp");
|
|
2753
|
+
add(/\b(commercial auto|business auto|automobile liability)\b/i, "commercial_auto");
|
|
2754
|
+
add(/\b(commercial property|property coverage|building coverage)\b/i, "commercial_property");
|
|
2755
|
+
return types.length ? types : ["other"];
|
|
2756
|
+
}
|
|
2757
|
+
function inferDocumentType(nodes) {
|
|
2758
|
+
const text = nodes.slice(0, 25).map(nodeText).join(" ").toLowerCase();
|
|
2759
|
+
if (/\b(quote|proposal|quotation|indication)\b/.test(text) && !/\bpolicy number\b/.test(text)) {
|
|
2760
|
+
return "quote";
|
|
2761
|
+
}
|
|
2762
|
+
return "policy";
|
|
2763
|
+
}
|
|
2764
|
+
function coverageNameFromRow(text) {
|
|
2765
|
+
const labelled = text.match(/\b(?:coverage|coverage part|line)\s*:?\s*([^|;$]{3,80})/i)?.[1];
|
|
2766
|
+
if (labelled) return cleanValue(labelled);
|
|
2767
|
+
const parts = text.split(/\s+\|\s+| {2,}|\t/).map(cleanValue).filter(Boolean);
|
|
2768
|
+
const first = parts.find(
|
|
2769
|
+
(part) => !/^(limit|limits?|deductible|premium|amount|basis|rate|retroactive|aggregate|each occurrence)$/i.test(part) && !/^\$?[\d,]+/.test(part)
|
|
2770
|
+
);
|
|
2771
|
+
return cleanValue(first);
|
|
2772
|
+
}
|
|
2773
|
+
function limitFromText(text) {
|
|
2774
|
+
return moneyValue(
|
|
2775
|
+
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]
|
|
2776
|
+
);
|
|
2777
|
+
}
|
|
2778
|
+
function deductibleFromText(text) {
|
|
2779
|
+
return moneyValue(text.match(/\b(?:deductible|retention|sir)\s*:?\s*(\$?\d[\d,]*(?:\.\d{2})?)/i)?.[1]);
|
|
2780
|
+
}
|
|
2781
|
+
function premiumFromText(text) {
|
|
2782
|
+
return moneyValue(text.match(/\b(?:premium|total premium|total cost|amount due)\s*:?\s*(\$?\d[\d,]*(?:\.\d{2})?)/i)?.[1]);
|
|
2783
|
+
}
|
|
2784
|
+
function buildCoverages(nodes) {
|
|
2785
|
+
const rows = nodes.filter((node) => {
|
|
2786
|
+
const text = nodeText(node);
|
|
2787
|
+
return (node.kind === "table_row" || node.kind === "schedule" || node.kind === "text") && /\b(coverage|limit|deductible|aggregate|occurrence|liability|premium)\b/i.test(text);
|
|
2788
|
+
});
|
|
2789
|
+
const coverages = [];
|
|
2790
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2791
|
+
for (const row of rows) {
|
|
2792
|
+
const text = nodeText(row);
|
|
2793
|
+
const name = coverageNameFromRow(text);
|
|
2794
|
+
const limit = limitFromText(text);
|
|
2795
|
+
const deductible = deductibleFromText(text);
|
|
2796
|
+
const premium = premiumFromText(text);
|
|
2797
|
+
if (!name || !limit && !deductible && !premium) continue;
|
|
2798
|
+
const key = [name.toLowerCase(), limit, deductible, premium].join("|");
|
|
2799
|
+
if (seen.has(key)) continue;
|
|
2800
|
+
seen.add(key);
|
|
2801
|
+
coverages.push({
|
|
2802
|
+
name,
|
|
2803
|
+
limit,
|
|
2804
|
+
deductible,
|
|
2805
|
+
premium,
|
|
2806
|
+
formNumber: typeof row.metadata?.formNumber === "string" ? row.metadata.formNumber : void 0,
|
|
2807
|
+
sourceNodeIds: [row.id],
|
|
2808
|
+
sourceSpanIds: row.sourceSpanIds
|
|
2809
|
+
});
|
|
2810
|
+
if (coverages.length >= 60) break;
|
|
2811
|
+
}
|
|
2812
|
+
return coverages;
|
|
2813
|
+
}
|
|
2814
|
+
function buildParties(profile) {
|
|
2815
|
+
const parties = [];
|
|
2816
|
+
if (profile.namedInsured) {
|
|
2817
|
+
parties.push({
|
|
2818
|
+
role: "named_insured",
|
|
2819
|
+
name: profile.namedInsured.value,
|
|
2820
|
+
sourceNodeIds: profile.namedInsured.sourceNodeIds,
|
|
2821
|
+
sourceSpanIds: profile.namedInsured.sourceSpanIds
|
|
2822
|
+
});
|
|
2823
|
+
}
|
|
2824
|
+
if (profile.insurer) {
|
|
2825
|
+
parties.push({
|
|
2826
|
+
role: "insurer",
|
|
2827
|
+
name: profile.insurer.value,
|
|
2828
|
+
sourceNodeIds: profile.insurer.sourceNodeIds,
|
|
2829
|
+
sourceSpanIds: profile.insurer.sourceSpanIds
|
|
2830
|
+
});
|
|
2831
|
+
}
|
|
2832
|
+
if (profile.broker) {
|
|
2833
|
+
parties.push({
|
|
2834
|
+
role: "broker",
|
|
2835
|
+
name: profile.broker.value,
|
|
2836
|
+
sourceNodeIds: profile.broker.sourceNodeIds,
|
|
2837
|
+
sourceSpanIds: profile.broker.sourceSpanIds
|
|
2838
|
+
});
|
|
2839
|
+
}
|
|
2840
|
+
return parties;
|
|
2841
|
+
}
|
|
2842
|
+
function buildEndorsementSupport(nodes) {
|
|
2843
|
+
const support = [];
|
|
2844
|
+
for (const node of nodes) {
|
|
2845
|
+
const text = nodeText(node);
|
|
2846
|
+
const add = (kind, status) => {
|
|
2847
|
+
if (support.some((item) => item.kind === kind && item.status === status && item.sourceNodeIds.includes(node.id))) {
|
|
2848
|
+
return;
|
|
2849
|
+
}
|
|
2850
|
+
support.push({
|
|
2851
|
+
kind,
|
|
2852
|
+
status,
|
|
2853
|
+
summary: node.textExcerpt ?? node.description,
|
|
2854
|
+
sourceNodeIds: [node.id],
|
|
2855
|
+
sourceSpanIds: node.sourceSpanIds
|
|
2856
|
+
});
|
|
2857
|
+
};
|
|
2858
|
+
if (/additional insured/i.test(text)) add("additional_insured", /not included|requires endorsement|only by endorsement/i.test(text) ? "requires_review" : "supported");
|
|
2859
|
+
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");
|
|
2860
|
+
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");
|
|
2861
|
+
if (/loss payee|mortgagee/i.test(text)) add(/mortgagee/i.test(text) ? "mortgagee" : "loss_payee", "supported");
|
|
2862
|
+
if (support.length >= 20) break;
|
|
2863
|
+
}
|
|
2864
|
+
return support;
|
|
2865
|
+
}
|
|
2866
|
+
function buildDeterministicOperationalProfile(params) {
|
|
2867
|
+
const nodes = params.sourceTree.filter((node) => node.kind !== "document");
|
|
2868
|
+
const partial = {
|
|
2869
|
+
documentType: inferDocumentType(nodes),
|
|
2870
|
+
policyTypes: inferPolicyTypes(nodes),
|
|
2871
|
+
policyNumber: firstMatch(nodes, [
|
|
2872
|
+
/\bpolicy\s*(?:number|no\.?|#)\s*:?\s*([A-Z0-9][A-Z0-9-]{4,})/i,
|
|
2873
|
+
/\bpolicy\s*[:#]\s*([A-Z0-9][A-Z0-9-]{4,})/i
|
|
2874
|
+
]),
|
|
2875
|
+
namedInsured: firstMatch(nodes, [
|
|
2876
|
+
/\b(?:named insured|insured name|insured)\s*:?\s*(.+?)(?=\s+(?:coverage|policy number|insurer|carrier|premium|effective|expiration)\b|[|;\n]|$)/i,
|
|
2877
|
+
/\b(?:applicant|policyholder)\s*:?\s*(.+?)(?=\s+(?:coverage|policy number|insurer|carrier|premium|effective|expiration)\b|[|;\n]|$)/i
|
|
2878
|
+
]),
|
|
2879
|
+
insurer: firstMatch(nodes, [
|
|
2880
|
+
/\b(?:insurer|carrier|company|security)\s*:?\s*([^|;\n]{3,120})/i,
|
|
2881
|
+
/\bunderwritten by\s+([^|;\n]{3,120})/i
|
|
2882
|
+
]),
|
|
2883
|
+
broker: firstMatch(nodes, [
|
|
2884
|
+
/\b(?:broker|producer|agent)\s*:?\s*([^|;\n]{3,120})/i
|
|
2885
|
+
]),
|
|
2886
|
+
effectiveDate: firstMatch(nodes, [
|
|
2887
|
+
/\b(?:effective date|policy period from|from)\s*:?\s*([0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4})/i,
|
|
2888
|
+
/\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
|
|
2889
|
+
]),
|
|
2890
|
+
expirationDate: firstMatch(nodes, [
|
|
2891
|
+
/\b(?:expiration date|expiry date|expires|to)\s*:?\s*([0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4})/i,
|
|
2892
|
+
/\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
|
|
2893
|
+
]),
|
|
2894
|
+
retroactiveDate: firstMatch(nodes, [
|
|
2895
|
+
/\bretroactive date\s*:?\s*([0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4}|full prior acts|none)/i
|
|
2896
|
+
]),
|
|
2897
|
+
premium: firstMatch(nodes, [
|
|
2898
|
+
/\b(?:total premium|premium|total cost|amount due)\s*:?\s*(\$?\d[\d,]*(?:\.\d{2})?)/i
|
|
2899
|
+
])
|
|
2900
|
+
};
|
|
2901
|
+
const coverages = buildCoverages(nodes);
|
|
2902
|
+
const coverageTypes = [...new Set(coverages.map((coverage) => coverage.name))];
|
|
2903
|
+
const sourceNodeIds = [.../* @__PURE__ */ new Set([
|
|
2904
|
+
...Object.values(partial).flatMap(
|
|
2905
|
+
(value) => value && typeof value === "object" && "sourceNodeIds" in value ? value.sourceNodeIds : []
|
|
2906
|
+
),
|
|
2907
|
+
...coverages.flatMap((coverage) => coverage.sourceNodeIds)
|
|
2908
|
+
])];
|
|
2909
|
+
const sourceSpanIds = [.../* @__PURE__ */ new Set([
|
|
2910
|
+
...Object.values(partial).flatMap(
|
|
2911
|
+
(value) => value && typeof value === "object" && "sourceSpanIds" in value ? value.sourceSpanIds : []
|
|
2912
|
+
),
|
|
2913
|
+
...coverages.flatMap((coverage) => coverage.sourceSpanIds)
|
|
2914
|
+
])];
|
|
2915
|
+
return PolicyOperationalProfileSchema.parse({
|
|
2916
|
+
...partial,
|
|
2917
|
+
coverageTypes,
|
|
2918
|
+
coverages,
|
|
2919
|
+
parties: buildParties(partial),
|
|
2920
|
+
endorsementSupport: buildEndorsementSupport(nodes),
|
|
2921
|
+
sourceNodeIds,
|
|
2922
|
+
sourceSpanIds,
|
|
2923
|
+
warnings: [
|
|
2924
|
+
...coverages.length === 0 ? ["No source-backed coverage schedule rows were identified deterministically."] : [],
|
|
2925
|
+
...!partial.policyNumber ? ["No source-backed policy number was identified deterministically."] : [],
|
|
2926
|
+
...!partial.namedInsured ? ["No source-backed named insured was identified deterministically."] : []
|
|
2927
|
+
]
|
|
2928
|
+
});
|
|
2929
|
+
}
|
|
2930
|
+
function mergeOperationalProfile(base, candidate, validNodeIds, validSpanIds) {
|
|
2931
|
+
const keepIds = (ids, valid) => Array.isArray(ids) ? ids.filter((id) => typeof id === "string" && valid.has(id)) : [];
|
|
2932
|
+
const mergeValue = (fallback, next) => {
|
|
2933
|
+
if (!next || typeof next !== "object" || Array.isArray(next)) return fallback;
|
|
2934
|
+
const record = next;
|
|
2935
|
+
const value = typeof record.value === "string" ? cleanValue(record.value) : void 0;
|
|
2936
|
+
if (!value) return fallback;
|
|
2937
|
+
const sourceNodeIds = keepIds(record.sourceNodeIds, validNodeIds);
|
|
2938
|
+
const sourceSpanIds = keepIds(record.sourceSpanIds, validSpanIds);
|
|
2939
|
+
if (sourceNodeIds.length === 0 && sourceSpanIds.length === 0) return fallback;
|
|
2940
|
+
return {
|
|
2941
|
+
value,
|
|
2942
|
+
normalizedValue: typeof record.normalizedValue === "string" ? record.normalizedValue : fallback?.normalizedValue,
|
|
2943
|
+
confidence: record.confidence === "high" || record.confidence === "low" || record.confidence === "medium" ? record.confidence : "medium",
|
|
2944
|
+
sourceNodeIds,
|
|
2945
|
+
sourceSpanIds
|
|
2946
|
+
};
|
|
2947
|
+
};
|
|
2948
|
+
const coverages = Array.isArray(candidate.coverages) ? candidate.coverages.map((coverage) => ({
|
|
2949
|
+
...coverage,
|
|
2950
|
+
sourceNodeIds: keepIds(coverage.sourceNodeIds, validNodeIds),
|
|
2951
|
+
sourceSpanIds: keepIds(coverage.sourceSpanIds, validSpanIds)
|
|
2952
|
+
})).filter((coverage) => coverage.name && (coverage.sourceNodeIds.length > 0 || coverage.sourceSpanIds.length > 0)) : base.coverages;
|
|
2953
|
+
return PolicyOperationalProfileSchema.parse({
|
|
2954
|
+
...base,
|
|
2955
|
+
documentType: candidate.documentType === "quote" ? "quote" : candidate.documentType === "policy" ? "policy" : base.documentType,
|
|
2956
|
+
policyTypes: Array.isArray(candidate.policyTypes) && candidate.policyTypes.length > 0 ? candidate.policyTypes : base.policyTypes,
|
|
2957
|
+
policyNumber: mergeValue(base.policyNumber, candidate.policyNumber),
|
|
2958
|
+
namedInsured: mergeValue(base.namedInsured, candidate.namedInsured),
|
|
2959
|
+
insurer: mergeValue(base.insurer, candidate.insurer),
|
|
2960
|
+
broker: mergeValue(base.broker, candidate.broker),
|
|
2961
|
+
effectiveDate: mergeValue(base.effectiveDate, candidate.effectiveDate),
|
|
2962
|
+
expirationDate: mergeValue(base.expirationDate, candidate.expirationDate),
|
|
2963
|
+
retroactiveDate: mergeValue(base.retroactiveDate, candidate.retroactiveDate),
|
|
2964
|
+
premium: mergeValue(base.premium, candidate.premium),
|
|
2965
|
+
coverageTypes: Array.isArray(candidate.coverageTypes) && candidate.coverageTypes.length > 0 ? candidate.coverageTypes : base.coverageTypes,
|
|
2966
|
+
coverages,
|
|
2967
|
+
parties: base.parties,
|
|
2968
|
+
endorsementSupport: base.endorsementSupport,
|
|
2969
|
+
sourceNodeIds: [.../* @__PURE__ */ new Set([...base.sourceNodeIds, ...keepIds(candidate.sourceNodeIds, validNodeIds)])],
|
|
2970
|
+
sourceSpanIds: [.../* @__PURE__ */ new Set([...base.sourceSpanIds, ...keepIds(candidate.sourceSpanIds, validSpanIds)])],
|
|
2971
|
+
warnings: base.warnings
|
|
2972
|
+
});
|
|
2973
|
+
}
|
|
2974
|
+
|
|
2284
2975
|
// src/extraction/pdf.ts
|
|
2285
2976
|
import {
|
|
2286
2977
|
PDFDocument,
|
|
@@ -2670,15 +3361,15 @@ function normalizeItem(ref, item) {
|
|
|
2670
3361
|
if (!text) return void 0;
|
|
2671
3362
|
const table = getItemTable(item);
|
|
2672
3363
|
const pages = (item.prov ?? []).map((prov) => getPageNumber(prov)).filter((page) => typeof page === "number" && page > 0);
|
|
2673
|
-
const
|
|
2674
|
-
const
|
|
3364
|
+
const pageStart2 = pages.length ? Math.min(...pages) : void 0;
|
|
3365
|
+
const pageEnd2 = pages.length ? Math.max(...pages) : pageStart2;
|
|
2675
3366
|
const bboxes = (item.prov ?? []).map((prov) => toSourceSpanBBox(prov)).filter((bbox) => Boolean(bbox));
|
|
2676
3367
|
return {
|
|
2677
3368
|
ref,
|
|
2678
3369
|
label: typeof item.label === "string" ? item.label : void 0,
|
|
2679
3370
|
text,
|
|
2680
|
-
pageStart,
|
|
2681
|
-
pageEnd,
|
|
3371
|
+
pageStart: pageStart2,
|
|
3372
|
+
pageEnd: pageEnd2,
|
|
2682
3373
|
bboxes: bboxes.length ? bboxes : void 0,
|
|
2683
3374
|
table
|
|
2684
3375
|
};
|
|
@@ -2690,7 +3381,7 @@ function buildSourceSpansForUnit(unit, index, options) {
|
|
|
2690
3381
|
doclingRef: unit.ref,
|
|
2691
3382
|
...unit.label ? { doclingLabel: unit.label } : {}
|
|
2692
3383
|
};
|
|
2693
|
-
const
|
|
3384
|
+
const tableId2 = unit.table ? `${unit.ref}:table` : void 0;
|
|
2694
3385
|
const tableSpan = withDoclingKind(buildSourceSpan(
|
|
2695
3386
|
{
|
|
2696
3387
|
documentId: options.documentId,
|
|
@@ -2700,7 +3391,7 @@ function buildSourceSpansForUnit(unit, index, options) {
|
|
|
2700
3391
|
pageEnd: unit.pageEnd,
|
|
2701
3392
|
sectionId: unit.label,
|
|
2702
3393
|
sourceUnit: unit.table ? "table" : labelToSourceUnit(unit.label),
|
|
2703
|
-
table:
|
|
3394
|
+
table: tableId2 ? { tableId: tableId2 } : void 0,
|
|
2704
3395
|
metadata: baseMetadata
|
|
2705
3396
|
},
|
|
2706
3397
|
index * 1e3
|
|
@@ -2724,7 +3415,7 @@ function buildSourceSpansForUnit(unit, index, options) {
|
|
|
2724
3415
|
sourceUnit: "table_row",
|
|
2725
3416
|
parentSpanId: tableSpan.id,
|
|
2726
3417
|
table: {
|
|
2727
|
-
tableId,
|
|
3418
|
+
tableId: tableId2,
|
|
2728
3419
|
tableSpanId: tableSpan.id,
|
|
2729
3420
|
rowIndex,
|
|
2730
3421
|
isHeader
|
|
@@ -2732,7 +3423,7 @@ function buildSourceSpansForUnit(unit, index, options) {
|
|
|
2732
3423
|
metadata: {
|
|
2733
3424
|
...baseMetadata,
|
|
2734
3425
|
sourceUnit: "table_row",
|
|
2735
|
-
tableId:
|
|
3426
|
+
tableId: tableId2 ?? "",
|
|
2736
3427
|
tableSpanId: tableSpan.id,
|
|
2737
3428
|
rowIndex: String(rowIndex),
|
|
2738
3429
|
isHeader: String(isHeader)
|
|
@@ -2756,7 +3447,7 @@ function buildSourceSpansForUnit(unit, index, options) {
|
|
|
2756
3447
|
sourceUnit: "table_cell",
|
|
2757
3448
|
parentSpanId: rowSpan.id,
|
|
2758
3449
|
table: {
|
|
2759
|
-
tableId,
|
|
3450
|
+
tableId: tableId2,
|
|
2760
3451
|
tableSpanId: tableSpan.id,
|
|
2761
3452
|
rowSpanId: rowSpan.id,
|
|
2762
3453
|
rowIndex,
|
|
@@ -2767,7 +3458,7 @@ function buildSourceSpansForUnit(unit, index, options) {
|
|
|
2767
3458
|
metadata: {
|
|
2768
3459
|
...baseMetadata,
|
|
2769
3460
|
sourceUnit: "table_cell",
|
|
2770
|
-
tableId:
|
|
3461
|
+
tableId: tableId2 ?? "",
|
|
2771
3462
|
tableSpanId: tableSpan.id,
|
|
2772
3463
|
rowSpanId: rowSpan.id,
|
|
2773
3464
|
rowIndex: String(rowIndex),
|
|
@@ -2922,7 +3613,7 @@ function buildSourceContext(spans, maxChars = 12e3) {
|
|
|
2922
3613
|
const lines = [];
|
|
2923
3614
|
let length = 0;
|
|
2924
3615
|
for (const span of orderSourceSpansForContext(spans)) {
|
|
2925
|
-
const unit =
|
|
3616
|
+
const unit = sourceUnit3(span);
|
|
2926
3617
|
const table = span.table;
|
|
2927
3618
|
const tableContext = [
|
|
2928
3619
|
unit ? ` unit:${unit}` : "",
|
|
@@ -2946,11 +3637,11 @@ ${lines.join("\n\n")}
|
|
|
2946
3637
|
|
|
2947
3638
|
Use sourceSpan IDs when grounding extracted contractual values.`;
|
|
2948
3639
|
}
|
|
2949
|
-
function
|
|
3640
|
+
function sourceUnit3(span) {
|
|
2950
3641
|
return span.sourceUnit ?? span.metadata?.sourceUnit;
|
|
2951
3642
|
}
|
|
2952
3643
|
function sourceContextRank(span) {
|
|
2953
|
-
switch (
|
|
3644
|
+
switch (sourceUnit3(span)) {
|
|
2954
3645
|
case "table_row":
|
|
2955
3646
|
return 0;
|
|
2956
3647
|
case "table":
|
|
@@ -2969,10 +3660,10 @@ function sourceContextRank(span) {
|
|
|
2969
3660
|
}
|
|
2970
3661
|
function orderSourceSpansForContext(spans) {
|
|
2971
3662
|
const parentRows = new Set(
|
|
2972
|
-
spans.filter((span) =>
|
|
3663
|
+
spans.filter((span) => sourceUnit3(span) === "table_row").map((span) => span.id)
|
|
2973
3664
|
);
|
|
2974
3665
|
const filtered = spans.filter((span) => {
|
|
2975
|
-
if (
|
|
3666
|
+
if (sourceUnit3(span) !== "table_cell") return true;
|
|
2976
3667
|
const parent = span.parentSpanId ?? span.table?.rowSpanId ?? span.metadata?.rowSpanId;
|
|
2977
3668
|
return !parent || !parentRows.has(parent);
|
|
2978
3669
|
});
|
|
@@ -3279,6 +3970,8 @@ function assembleDocument(documentId, documentType, memory) {
|
|
|
3279
3970
|
carrier: readRecordValue(carrier, "carrierName") ?? "Unknown",
|
|
3280
3971
|
insuredName: readRecordValue(insured, "insuredName") ?? "Unknown",
|
|
3281
3972
|
coverages: coverageRecords,
|
|
3973
|
+
documentMetadata: {},
|
|
3974
|
+
documentOutline: [],
|
|
3282
3975
|
policyTypes: readRecordValue(classify, "policyTypes"),
|
|
3283
3976
|
...sanitizeNulls(carrier ?? {}),
|
|
3284
3977
|
...sanitizeNulls(insured ?? {}),
|
|
@@ -3330,6 +4023,247 @@ function assembleDocument(documentId, documentType, memory) {
|
|
|
3330
4023
|
return doc;
|
|
3331
4024
|
}
|
|
3332
4025
|
|
|
4026
|
+
// src/extraction/document-structure.ts
|
|
4027
|
+
var FACT_ARRAY_PATHS = [
|
|
4028
|
+
"coverages",
|
|
4029
|
+
"enrichedCoverages",
|
|
4030
|
+
"endorsements",
|
|
4031
|
+
"exclusions",
|
|
4032
|
+
"conditions",
|
|
4033
|
+
"definitions",
|
|
4034
|
+
"coveredReasons",
|
|
4035
|
+
"taxesAndFees",
|
|
4036
|
+
"premiumBreakdown",
|
|
4037
|
+
"supplementaryFacts"
|
|
4038
|
+
];
|
|
4039
|
+
function slugPart(value) {
|
|
4040
|
+
const text = String(value ?? "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
4041
|
+
return text || "node";
|
|
4042
|
+
}
|
|
4043
|
+
function numberValue(record, ...keys) {
|
|
4044
|
+
for (const key of keys) {
|
|
4045
|
+
const value = record[key];
|
|
4046
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
4047
|
+
}
|
|
4048
|
+
return void 0;
|
|
4049
|
+
}
|
|
4050
|
+
function stringValue2(record, ...keys) {
|
|
4051
|
+
for (const key of keys) {
|
|
4052
|
+
const value = record[key];
|
|
4053
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
4054
|
+
}
|
|
4055
|
+
return void 0;
|
|
4056
|
+
}
|
|
4057
|
+
function stringArray(value) {
|
|
4058
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string" && item.length > 0) : [];
|
|
4059
|
+
}
|
|
4060
|
+
function sourceUnit4(span) {
|
|
4061
|
+
return span.sourceUnit ?? span.metadata?.sourceUnit;
|
|
4062
|
+
}
|
|
4063
|
+
function spanPage(span) {
|
|
4064
|
+
return span.pageStart ?? span.location?.page ?? span.location?.startPage;
|
|
4065
|
+
}
|
|
4066
|
+
function spanPageEnd(span) {
|
|
4067
|
+
return span.pageEnd ?? span.location?.endPage ?? spanPage(span);
|
|
4068
|
+
}
|
|
4069
|
+
function sourceSpansForPage(sourceSpans, page) {
|
|
4070
|
+
return sourceSpans.filter((span) => spanPage(span) === page && sourceUnit4(span) === "page").map((span) => span.id);
|
|
4071
|
+
}
|
|
4072
|
+
function nodePageOverlaps(node, record) {
|
|
4073
|
+
const recordStart = numberValue(record, "pageNumber", "pageStart", "resolvedFromPage");
|
|
4074
|
+
const recordEnd = numberValue(record, "pageNumber", "pageEnd", "resolvedFromPage") ?? recordStart;
|
|
4075
|
+
if (!recordStart) return false;
|
|
4076
|
+
const nodeStart = node.pageStart ?? node.pageEnd;
|
|
4077
|
+
const nodeEnd = node.pageEnd ?? node.pageStart;
|
|
4078
|
+
if (!nodeStart) return false;
|
|
4079
|
+
return recordStart <= (nodeEnd ?? nodeStart) && (recordEnd ?? recordStart) >= nodeStart;
|
|
4080
|
+
}
|
|
4081
|
+
function nodeFormMatches(node, record) {
|
|
4082
|
+
const formNumber = stringValue2(record, "formNumber");
|
|
4083
|
+
return Boolean(formNumber && node.formNumber && formNumber.toLowerCase() === node.formNumber.toLowerCase());
|
|
4084
|
+
}
|
|
4085
|
+
function nodeSourceOverlaps(node, record) {
|
|
4086
|
+
const nodeSourceIds = new Set(node.sourceSpanIds ?? []);
|
|
4087
|
+
if (nodeSourceIds.size === 0) return false;
|
|
4088
|
+
return stringArray(record.sourceSpanIds).some((id) => nodeSourceIds.has(id));
|
|
4089
|
+
}
|
|
4090
|
+
function findBestNode(nodes, record) {
|
|
4091
|
+
let best;
|
|
4092
|
+
const visit = (node) => {
|
|
4093
|
+
let score = 0;
|
|
4094
|
+
if (nodeSourceOverlaps(node, record)) score += 8;
|
|
4095
|
+
if (nodeFormMatches(node, record)) score += 4;
|
|
4096
|
+
if (nodePageOverlaps(node, record)) score += 3;
|
|
4097
|
+
if (score > 0 && (!best || score > best.score)) {
|
|
4098
|
+
best = { node, score };
|
|
4099
|
+
}
|
|
4100
|
+
for (const child of node.children ?? []) visit(child);
|
|
4101
|
+
};
|
|
4102
|
+
for (const node of nodes) visit(node);
|
|
4103
|
+
return best?.node;
|
|
4104
|
+
}
|
|
4105
|
+
function attachDocumentNodeIds(document, nodes) {
|
|
4106
|
+
const doc = document;
|
|
4107
|
+
for (const path of FACT_ARRAY_PATHS) {
|
|
4108
|
+
const value = doc[path];
|
|
4109
|
+
if (!Array.isArray(value)) continue;
|
|
4110
|
+
doc[path] = value.map((item) => {
|
|
4111
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) return item;
|
|
4112
|
+
const record = item;
|
|
4113
|
+
if (typeof record.documentNodeId === "string" && record.documentNodeId.length > 0) return record;
|
|
4114
|
+
const node = findBestNode(nodes, record);
|
|
4115
|
+
return node ? { ...record, documentNodeId: node.id } : record;
|
|
4116
|
+
});
|
|
4117
|
+
}
|
|
4118
|
+
}
|
|
4119
|
+
function buildNodeFromSection(section, index) {
|
|
4120
|
+
const title = stringValue2(section, "title", "name", "sectionRef") ?? `Section ${index + 1}`;
|
|
4121
|
+
const id = stringValue2(section, "documentNodeId", "recordId") ?? `section:${index}:${slugPart(title)}`;
|
|
4122
|
+
const pageStart2 = numberValue(section, "pageStart", "pageNumber");
|
|
4123
|
+
const pageEnd2 = numberValue(section, "pageEnd", "pageNumber") ?? pageStart2;
|
|
4124
|
+
const type = stringValue2(section, "type");
|
|
4125
|
+
const coverageType = stringValue2(section, "coverageType");
|
|
4126
|
+
const sourceSpanIds = stringArray(section.sourceSpanIds);
|
|
4127
|
+
const children = Array.isArray(section.subsections) ? section.subsections.filter((item) => Boolean(item) && typeof item === "object" && !Array.isArray(item)).map((subsection, childIndex) => {
|
|
4128
|
+
const childTitle = stringValue2(subsection, "title", "name") ?? `${title} ${childIndex + 1}`;
|
|
4129
|
+
const childId = stringValue2(subsection, "documentNodeId", "recordId") ?? `${id}:subsection:${childIndex}:${slugPart(childTitle)}`;
|
|
4130
|
+
return {
|
|
4131
|
+
id: childId,
|
|
4132
|
+
title: childTitle,
|
|
4133
|
+
originalTitle: childTitle,
|
|
4134
|
+
type,
|
|
4135
|
+
label: type,
|
|
4136
|
+
level: 2,
|
|
4137
|
+
sectionNumber: stringValue2(subsection, "sectionNumber"),
|
|
4138
|
+
pageStart: numberValue(subsection, "pageNumber") ?? pageStart2,
|
|
4139
|
+
pageEnd: numberValue(subsection, "pageNumber") ?? pageStart2,
|
|
4140
|
+
excerpt: stringValue2(subsection, "excerpt"),
|
|
4141
|
+
content: stringValue2(subsection, "content"),
|
|
4142
|
+
sourceSpanIds: stringArray(subsection.sourceSpanIds),
|
|
4143
|
+
sourceTextHash: stringValue2(subsection, "sourceTextHash")
|
|
4144
|
+
};
|
|
4145
|
+
}) : void 0;
|
|
4146
|
+
return {
|
|
4147
|
+
id,
|
|
4148
|
+
title,
|
|
4149
|
+
originalTitle: title,
|
|
4150
|
+
type,
|
|
4151
|
+
label: type,
|
|
4152
|
+
level: 1,
|
|
4153
|
+
sectionNumber: stringValue2(section, "sectionNumber"),
|
|
4154
|
+
pageStart: pageStart2,
|
|
4155
|
+
pageEnd: pageEnd2,
|
|
4156
|
+
formNumber: stringValue2(section, "formNumber"),
|
|
4157
|
+
formTitle: stringValue2(section, "formTitle"),
|
|
4158
|
+
excerpt: stringValue2(section, "excerpt"),
|
|
4159
|
+
content: stringValue2(section, "content"),
|
|
4160
|
+
interpretationLabels: [type, coverageType].filter((value) => Boolean(value)),
|
|
4161
|
+
sourceSpanIds: sourceSpanIds.length > 0 ? sourceSpanIds : void 0,
|
|
4162
|
+
sourceTextHash: stringValue2(section, "sourceTextHash"),
|
|
4163
|
+
children: children && children.length > 0 ? children : void 0
|
|
4164
|
+
};
|
|
4165
|
+
}
|
|
4166
|
+
function buildNodesFromSourceSpans(sourceSpans) {
|
|
4167
|
+
const candidates = sourceSpans.filter((span) => {
|
|
4168
|
+
const unit = sourceUnit4(span);
|
|
4169
|
+
return unit === "section" || unit === "section_candidate" || unit === "page";
|
|
4170
|
+
});
|
|
4171
|
+
return candidates.sort((left, right) => (spanPage(left) ?? 0) - (spanPage(right) ?? 0) || left.id.localeCompare(right.id)).map((span, index) => {
|
|
4172
|
+
const title = span.sectionId ?? span.formNumber ?? (sourceUnit4(span) === "page" && spanPage(span) ? `Page ${spanPage(span)}` : `Source unit ${index + 1}`);
|
|
4173
|
+
return {
|
|
4174
|
+
id: `source:${index}:${slugPart(span.id)}`,
|
|
4175
|
+
title,
|
|
4176
|
+
originalTitle: title,
|
|
4177
|
+
type: sourceUnit4(span),
|
|
4178
|
+
label: sourceUnit4(span),
|
|
4179
|
+
level: 1,
|
|
4180
|
+
pageStart: spanPage(span),
|
|
4181
|
+
pageEnd: spanPageEnd(span),
|
|
4182
|
+
formNumber: span.formNumber,
|
|
4183
|
+
excerpt: span.text.slice(0, 500),
|
|
4184
|
+
sourceSpanIds: [span.id],
|
|
4185
|
+
sourceTextHash: span.textHash ?? span.hash
|
|
4186
|
+
};
|
|
4187
|
+
});
|
|
4188
|
+
}
|
|
4189
|
+
function flattenToc(nodes) {
|
|
4190
|
+
const entries = [];
|
|
4191
|
+
const visit = (node) => {
|
|
4192
|
+
entries.push({
|
|
4193
|
+
title: node.title,
|
|
4194
|
+
level: node.level,
|
|
4195
|
+
pageStart: node.pageStart,
|
|
4196
|
+
pageEnd: node.pageEnd,
|
|
4197
|
+
documentNodeId: node.id,
|
|
4198
|
+
sourceSpanIds: node.sourceSpanIds
|
|
4199
|
+
});
|
|
4200
|
+
for (const child of node.children ?? []) visit(child);
|
|
4201
|
+
};
|
|
4202
|
+
for (const node of nodes) visit(node);
|
|
4203
|
+
return entries;
|
|
4204
|
+
}
|
|
4205
|
+
function buildPageMap(pageAssignments, sourceSpans, document) {
|
|
4206
|
+
const forms = document.formInventory ?? [];
|
|
4207
|
+
return pageAssignments.sort((left, right) => left.localPageNumber - right.localPageNumber).map((assignment) => {
|
|
4208
|
+
const form = forms.find((item) => {
|
|
4209
|
+
const start = item.pageStart;
|
|
4210
|
+
const end = item.pageEnd ?? start;
|
|
4211
|
+
return start != null && end != null && assignment.localPageNumber >= start && assignment.localPageNumber <= end;
|
|
4212
|
+
});
|
|
4213
|
+
return {
|
|
4214
|
+
page: assignment.localPageNumber,
|
|
4215
|
+
label: assignment.notes,
|
|
4216
|
+
formNumber: form?.formNumber,
|
|
4217
|
+
formTitle: form?.title,
|
|
4218
|
+
extractorNames: assignment.extractorNames,
|
|
4219
|
+
sourceSpanIds: sourceSpansForPage(sourceSpans, assignment.localPageNumber)
|
|
4220
|
+
};
|
|
4221
|
+
});
|
|
4222
|
+
}
|
|
4223
|
+
function buildAgentGuidance(document) {
|
|
4224
|
+
const guidance = [
|
|
4225
|
+
{
|
|
4226
|
+
kind: "source_structure",
|
|
4227
|
+
title: "Use the source outline as navigation",
|
|
4228
|
+
detail: "The documentOutline preserves source order and page ranges. Treat interpretation labels as hints, not as a replacement for the source document structure."
|
|
4229
|
+
}
|
|
4230
|
+
];
|
|
4231
|
+
if (document.declarations) {
|
|
4232
|
+
guidance.push({
|
|
4233
|
+
kind: "declarations",
|
|
4234
|
+
title: "Declarations establish policy facts",
|
|
4235
|
+
detail: "Declarations and schedules generally establish named insured, policy period, limits, deductibles, premium, and rating facts unless modified elsewhere."
|
|
4236
|
+
});
|
|
4237
|
+
}
|
|
4238
|
+
if (document.endorsements?.length || document.formInventory?.some((form) => form.formType === "endorsement")) {
|
|
4239
|
+
guidance.push({
|
|
4240
|
+
kind: "endorsement_override",
|
|
4241
|
+
title: "Endorsements may override base terms",
|
|
4242
|
+
detail: "Endorsements and change forms can add, remove, or override base policy wording. When terms conflict, inspect the effective endorsement language and source page."
|
|
4243
|
+
});
|
|
4244
|
+
}
|
|
4245
|
+
return guidance;
|
|
4246
|
+
}
|
|
4247
|
+
function attachDocumentStructure(params) {
|
|
4248
|
+
const docRecord = params.document;
|
|
4249
|
+
const sections = Array.isArray(params.document.sections) ? params.document.sections : [];
|
|
4250
|
+
const existingOutline = Array.isArray(docRecord.documentOutline) ? docRecord.documentOutline : [];
|
|
4251
|
+
const documentOutline = existingOutline.length > 0 ? existingOutline : sections.length > 0 ? sections.map((section, index) => buildNodeFromSection(section, index)) : buildNodesFromSourceSpans(params.sourceSpans);
|
|
4252
|
+
if (documentOutline.length > 0) {
|
|
4253
|
+
attachDocumentNodeIds(params.document, documentOutline);
|
|
4254
|
+
}
|
|
4255
|
+
const metadata = {
|
|
4256
|
+
...docRecord.documentMetadata && typeof docRecord.documentMetadata === "object" ? docRecord.documentMetadata : {},
|
|
4257
|
+
...params.document.formInventory?.length ? { formInventory: params.document.formInventory } : {},
|
|
4258
|
+
...documentOutline.length > 0 ? { tableOfContents: flattenToc(documentOutline) } : {},
|
|
4259
|
+
...params.pageAssignments.length > 0 ? { pageMap: buildPageMap(params.pageAssignments, params.sourceSpans, params.document) } : {},
|
|
4260
|
+
agentGuidance: buildAgentGuidance(params.document)
|
|
4261
|
+
};
|
|
4262
|
+
docRecord.documentMetadata = metadata;
|
|
4263
|
+
docRecord.documentOutline = documentOutline;
|
|
4264
|
+
return params.document;
|
|
4265
|
+
}
|
|
4266
|
+
|
|
3333
4267
|
// src/prompts/coordinator/format.ts
|
|
3334
4268
|
function buildFormatPrompt(entries) {
|
|
3335
4269
|
const block = entries.map((e) => `===ENTRY ${e.id}===
|
|
@@ -3929,6 +4863,8 @@ function chunkDocument(doc) {
|
|
|
3929
4863
|
{
|
|
3930
4864
|
formNumber: form.formNumber,
|
|
3931
4865
|
formType: form.formType,
|
|
4866
|
+
documentNodeId: form.documentNodeId,
|
|
4867
|
+
sourceSpanIds: form.sourceSpanIds?.join(","),
|
|
3932
4868
|
documentType: doc.type
|
|
3933
4869
|
}
|
|
3934
4870
|
);
|
|
@@ -3955,6 +4891,7 @@ function chunkDocument(doc) {
|
|
|
3955
4891
|
formNumber: end.formNumber,
|
|
3956
4892
|
pageStart: end.pageStart,
|
|
3957
4893
|
pageEnd: end.pageEnd,
|
|
4894
|
+
documentNodeId: end.documentNodeId,
|
|
3958
4895
|
sourceSpanIds: end.sourceSpanIds?.join(","),
|
|
3959
4896
|
sourceTextHash: end.sourceTextHash,
|
|
3960
4897
|
documentType: doc.type
|
|
@@ -3966,6 +4903,8 @@ function chunkDocument(doc) {
|
|
|
3966
4903
|
${exc.content}`.trim(), {
|
|
3967
4904
|
formNumber: exc.formNumber,
|
|
3968
4905
|
pageNumber: exc.pageNumber,
|
|
4906
|
+
documentNodeId: exc.documentNodeId,
|
|
4907
|
+
sourceSpanIds: exc.sourceSpanIds?.join(","),
|
|
3969
4908
|
documentType: doc.type
|
|
3970
4909
|
});
|
|
3971
4910
|
});
|
|
@@ -3983,6 +4922,8 @@ ${exc.content}`.trim(), {
|
|
|
3983
4922
|
conditionName: cond.name,
|
|
3984
4923
|
conditionType: cond.conditionType,
|
|
3985
4924
|
pageNumber: cond.pageNumber,
|
|
4925
|
+
documentNodeId: cond.documentNodeId,
|
|
4926
|
+
sourceSpanIds: cond.sourceSpanIds?.join(","),
|
|
3986
4927
|
documentType: doc.type
|
|
3987
4928
|
}
|
|
3988
4929
|
);
|
|
@@ -4004,6 +4945,9 @@ ${exc.content}`.trim(), {
|
|
|
4004
4945
|
formTitle: firstString2(definition, ["formTitle"]),
|
|
4005
4946
|
pageNumber: typeof definition.pageNumber === "number" ? definition.pageNumber : void 0,
|
|
4006
4947
|
sectionRef: firstString2(definition, ["sectionRef", "sectionTitle"]),
|
|
4948
|
+
documentNodeId: firstString2(definition, ["documentNodeId"]),
|
|
4949
|
+
sourceSpanIds: Array.isArray(definition.sourceSpanIds) ? definition.sourceSpanIds.join(",") : void 0,
|
|
4950
|
+
sourceTextHash: firstString2(definition, ["sourceTextHash"]),
|
|
4007
4951
|
documentType: doc.type
|
|
4008
4952
|
}
|
|
4009
4953
|
);
|
|
@@ -4032,6 +4976,9 @@ ${exc.content}`.trim(), {
|
|
|
4032
4976
|
formTitle: firstString2(coveredReason, ["formTitle"]),
|
|
4033
4977
|
pageNumber: typeof coveredReason.pageNumber === "number" ? coveredReason.pageNumber : void 0,
|
|
4034
4978
|
sectionRef: firstString2(coveredReason, ["sectionRef", "sectionTitle"]),
|
|
4979
|
+
documentNodeId: firstString2(coveredReason, ["documentNodeId"]),
|
|
4980
|
+
sourceSpanIds: Array.isArray(coveredReason.sourceSpanIds) ? coveredReason.sourceSpanIds.join(",") : void 0,
|
|
4981
|
+
sourceTextHash: firstString2(coveredReason, ["sourceTextHash"]),
|
|
4035
4982
|
documentType: doc.type
|
|
4036
4983
|
}
|
|
4037
4984
|
);
|
|
@@ -4093,6 +5040,7 @@ ${declLines.join("\n")}`, declMeta);
|
|
|
4093
5040
|
evidenceKind: "navigation",
|
|
4094
5041
|
sectionType: sec.type,
|
|
4095
5042
|
sectionNumber: sec.sectionNumber,
|
|
5043
|
+
documentNodeId: sec.documentNodeId,
|
|
4096
5044
|
pageStart: sec.pageStart,
|
|
4097
5045
|
pageEnd: sec.pageEnd,
|
|
4098
5046
|
sourceSpanIds: sec.sourceSpanIds?.join(","),
|
|
@@ -4116,6 +5064,7 @@ ${declLines.join("\n")}`, declMeta);
|
|
|
4116
5064
|
sectionType: sec.type,
|
|
4117
5065
|
parentSection: sec.title,
|
|
4118
5066
|
sectionNumber: sub.sectionNumber,
|
|
5067
|
+
documentNodeId: sub.documentNodeId,
|
|
4119
5068
|
pageNumber: sub.pageNumber,
|
|
4120
5069
|
sourceSpanIds: sub.sourceSpanIds?.join(","),
|
|
4121
5070
|
sourceTextHash: sub.sourceTextHash,
|
|
@@ -4124,6 +5073,31 @@ ${declLines.join("\n")}`, declMeta);
|
|
|
4124
5073
|
);
|
|
4125
5074
|
});
|
|
4126
5075
|
});
|
|
5076
|
+
asRecordArray(extendedDoc.documentOutline).forEach((node, i) => {
|
|
5077
|
+
const title = firstString2(node, ["title", "originalTitle"]) ?? `Document Node ${i + 1}`;
|
|
5078
|
+
const children = asRecordArray(node.children);
|
|
5079
|
+
pushChunk(
|
|
5080
|
+
`section:outline:${i}`,
|
|
5081
|
+
"section",
|
|
5082
|
+
lines([
|
|
5083
|
+
`Document Outline: ${title}`,
|
|
5084
|
+
firstString2(node, ["label", "type"]) ? `Label: ${firstString2(node, ["label", "type"])}` : null,
|
|
5085
|
+
typeof node.pageStart === "number" ? `Pages: ${node.pageStart}${typeof node.pageEnd === "number" ? `-${node.pageEnd}` : ""}` : null,
|
|
5086
|
+
firstString2(node, ["excerpt", "content"]),
|
|
5087
|
+
children.length > 0 ? `Children: ${children.map((child, childIndex) => firstString2(child, ["title", "originalTitle"]) ?? `Child ${childIndex + 1}`).join(", ")}` : null
|
|
5088
|
+
]),
|
|
5089
|
+
{
|
|
5090
|
+
evidenceKind: "navigation",
|
|
5091
|
+
documentNodeId: firstString2(node, ["id"]),
|
|
5092
|
+
sectionType: firstString2(node, ["type", "label"]),
|
|
5093
|
+
pageStart: typeof node.pageStart === "number" ? node.pageStart : void 0,
|
|
5094
|
+
pageEnd: typeof node.pageEnd === "number" ? node.pageEnd : void 0,
|
|
5095
|
+
sourceSpanIds: Array.isArray(node.sourceSpanIds) ? node.sourceSpanIds.join(",") : void 0,
|
|
5096
|
+
sourceTextHash: firstString2(node, ["sourceTextHash"]),
|
|
5097
|
+
documentType: doc.type
|
|
5098
|
+
}
|
|
5099
|
+
);
|
|
5100
|
+
});
|
|
4127
5101
|
doc.locations?.forEach((loc, i) => {
|
|
4128
5102
|
chunks.push({
|
|
4129
5103
|
id: `${docId}:location:${i}`,
|
|
@@ -6947,13 +7921,13 @@ async function resolveReferentialCoverages(params) {
|
|
|
6947
7921
|
function textValue(value) {
|
|
6948
7922
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
6949
7923
|
}
|
|
6950
|
-
function
|
|
7924
|
+
function numberValue2(value) {
|
|
6951
7925
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
6952
7926
|
}
|
|
6953
7927
|
function normalize(value) {
|
|
6954
7928
|
return value.toLowerCase().replace(/&/g, "and").replace(/[^a-z0-9]+/g, " ").trim();
|
|
6955
7929
|
}
|
|
6956
|
-
function
|
|
7930
|
+
function sourceUnit5(span) {
|
|
6957
7931
|
return span.sourceUnit ?? span.metadata?.sourceUnit;
|
|
6958
7932
|
}
|
|
6959
7933
|
function pageNumber(span) {
|
|
@@ -7023,7 +7997,7 @@ function firstField(fields, patterns) {
|
|
|
7023
7997
|
}
|
|
7024
7998
|
function coverageFromRow(span) {
|
|
7025
7999
|
const rowText = span.text.trim();
|
|
7026
|
-
if (!rowText ||
|
|
8000
|
+
if (!rowText || sourceUnit5(span) !== "table_row") return void 0;
|
|
7027
8001
|
if (span.table?.isHeader || span.metadata?.isHeader === "true") return void 0;
|
|
7028
8002
|
const fields = splitRowFields(rowText);
|
|
7029
8003
|
let name;
|
|
@@ -7085,7 +8059,7 @@ function coverageKey(coverage) {
|
|
|
7085
8059
|
textValue(coverage.name) ?? "",
|
|
7086
8060
|
textValue(coverage.limit) ?? "",
|
|
7087
8061
|
textValue(coverage.limitType) ?? "",
|
|
7088
|
-
|
|
8062
|
+
numberValue2(coverage.pageNumber) ?? ""
|
|
7089
8063
|
].map((part) => normalize(String(part))).join("|");
|
|
7090
8064
|
}
|
|
7091
8065
|
function rowMatchesExisting(row, existing) {
|
|
@@ -7103,7 +8077,7 @@ function recoverCoverageScheduleRows(params) {
|
|
|
7103
8077
|
const payload = params.memory.get("coverage_limits");
|
|
7104
8078
|
const existing = Array.isArray(payload?.coverages) ? payload.coverages : [];
|
|
7105
8079
|
const pages = coveragePages(params.pageAssignments);
|
|
7106
|
-
const candidates = params.sourceSpans.filter((span) =>
|
|
8080
|
+
const candidates = params.sourceSpans.filter((span) => sourceUnit5(span) === "table_row").filter((span) => {
|
|
7107
8081
|
const page = pageNumber(span);
|
|
7108
8082
|
return page !== void 0 && pages.has(page);
|
|
7109
8083
|
}).map(coverageFromRow).filter((coverage) => Boolean(coverage));
|
|
@@ -7739,13 +8713,13 @@ function buildPlanFromPageAssignments(pageAssignments, pageCount, formInventory)
|
|
|
7739
8713
|
const expanded = new Set(pages);
|
|
7740
8714
|
for (const page of pages) {
|
|
7741
8715
|
for (const form of contextualForms) {
|
|
7742
|
-
const
|
|
7743
|
-
const
|
|
8716
|
+
const pageStart2 = form.pageStart;
|
|
8717
|
+
const pageEnd2 = form.pageEnd ?? form.pageStart;
|
|
7744
8718
|
const formType = form.formType;
|
|
7745
8719
|
const supportsContextualExpansion = extractorName === "endorsements" ? formType === "endorsement" : formType === "coverage" || formType === "endorsement";
|
|
7746
8720
|
if (!supportsContextualExpansion) continue;
|
|
7747
|
-
if (page <
|
|
7748
|
-
for (let current =
|
|
8721
|
+
if (page < pageStart2 || page > pageEnd2) continue;
|
|
8722
|
+
for (let current = pageStart2; current <= pageEnd2; current += 1) {
|
|
7749
8723
|
expanded.add(current);
|
|
7750
8724
|
}
|
|
7751
8725
|
}
|
|
@@ -7778,7 +8752,10 @@ var ARRAY_PATHS = [
|
|
|
7778
8752
|
{ memoryKey: "sections", arrayKeys: ["sections"] },
|
|
7779
8753
|
{ memoryKey: "definitions", arrayKeys: ["definitions"] },
|
|
7780
8754
|
{ memoryKey: "covered_reasons", arrayKeys: ["coveredReasons", "covered_reasons"] },
|
|
7781
|
-
{ memoryKey: "declarations", arrayKeys: ["fields"] }
|
|
8755
|
+
{ memoryKey: "declarations", arrayKeys: ["fields"] },
|
|
8756
|
+
{ memoryKey: "premium_breakdown", arrayKeys: ["premiumBreakdown", "taxesAndFees"] },
|
|
8757
|
+
{ memoryKey: "supplementary", arrayKeys: ["auxiliaryFacts", "supplementaryFacts"] },
|
|
8758
|
+
{ memoryKey: "form_inventory", arrayKeys: ["forms"] }
|
|
7782
8759
|
];
|
|
7783
8760
|
function normalize2(value) {
|
|
7784
8761
|
return value.replace(/\s+/g, " ").trim().toLowerCase();
|
|
@@ -7790,7 +8767,7 @@ function textValue2(record, ...keys) {
|
|
|
7790
8767
|
}
|
|
7791
8768
|
return void 0;
|
|
7792
8769
|
}
|
|
7793
|
-
function
|
|
8770
|
+
function numberValue3(record, ...keys) {
|
|
7794
8771
|
for (const key of keys) {
|
|
7795
8772
|
const value = record[key];
|
|
7796
8773
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
@@ -7823,11 +8800,11 @@ function textMatches(record, span) {
|
|
|
7823
8800
|
function sourceHashFor(spans) {
|
|
7824
8801
|
return spans.map((span) => span.textHash ?? span.hash).filter(Boolean).join(":") || void 0;
|
|
7825
8802
|
}
|
|
7826
|
-
function
|
|
8803
|
+
function sourceUnit6(span) {
|
|
7827
8804
|
return span.sourceUnit ?? span.metadata?.sourceUnit;
|
|
7828
8805
|
}
|
|
7829
8806
|
function hierarchyScore(span) {
|
|
7830
|
-
switch (
|
|
8807
|
+
switch (sourceUnit6(span)) {
|
|
7831
8808
|
case "table_row":
|
|
7832
8809
|
return 5;
|
|
7833
8810
|
case "table":
|
|
@@ -7850,8 +8827,8 @@ function preferParentRows(matches, sourceSpans) {
|
|
|
7850
8827
|
const expanded = [];
|
|
7851
8828
|
const seen = /* @__PURE__ */ new Set();
|
|
7852
8829
|
for (const match of matches) {
|
|
7853
|
-
const parent =
|
|
7854
|
-
const preferred = parent &&
|
|
8830
|
+
const parent = sourceUnit6(match) === "table_cell" ? byId.get(parentRowId(match) ?? "") : void 0;
|
|
8831
|
+
const preferred = parent && sourceUnit6(parent) === "table_row" ? parent : match;
|
|
7855
8832
|
if (seen.has(preferred.id)) continue;
|
|
7856
8833
|
seen.add(preferred.id);
|
|
7857
8834
|
expanded.push(preferred);
|
|
@@ -7860,11 +8837,11 @@ function preferParentRows(matches, sourceSpans) {
|
|
|
7860
8837
|
}
|
|
7861
8838
|
function findSourceSpansForRecord(record, sourceSpans) {
|
|
7862
8839
|
if (sourceSpans.length === 0) return [];
|
|
7863
|
-
const
|
|
7864
|
-
const
|
|
8840
|
+
const pageStart2 = numberValue3(record, "pageNumber", "pageStart");
|
|
8841
|
+
const pageEnd2 = numberValue3(record, "pageNumber", "pageEnd");
|
|
7865
8842
|
const scored = sourceSpans.map((span) => {
|
|
7866
8843
|
let score = 0;
|
|
7867
|
-
if (pageOverlaps(
|
|
8844
|
+
if (pageOverlaps(pageStart2, pageEnd2, span)) score += 4;
|
|
7868
8845
|
if (formMatches(record, span)) score += 3;
|
|
7869
8846
|
if (textMatches(record, span)) score += 2;
|
|
7870
8847
|
if (score > 0) score += hierarchyScore(span);
|
|
@@ -7903,6 +8880,422 @@ function groundExtractionMemoryWithSourceSpans(memory, sourceSpans) {
|
|
|
7903
8880
|
}
|
|
7904
8881
|
}
|
|
7905
8882
|
|
|
8883
|
+
// src/extraction/source-tree-extractor.ts
|
|
8884
|
+
import { z as z41 } from "zod";
|
|
8885
|
+
var ORGANIZABLE_KINDS = [
|
|
8886
|
+
"page_group",
|
|
8887
|
+
"form",
|
|
8888
|
+
"endorsement",
|
|
8889
|
+
"section",
|
|
8890
|
+
"schedule",
|
|
8891
|
+
"clause"
|
|
8892
|
+
];
|
|
8893
|
+
var SourceTreeOrganizationSchema = z41.object({
|
|
8894
|
+
labels: z41.array(z41.object({
|
|
8895
|
+
nodeId: z41.string(),
|
|
8896
|
+
kind: z41.enum([
|
|
8897
|
+
"document",
|
|
8898
|
+
"page_group",
|
|
8899
|
+
"page",
|
|
8900
|
+
"form",
|
|
8901
|
+
"endorsement",
|
|
8902
|
+
"section",
|
|
8903
|
+
"schedule",
|
|
8904
|
+
"clause",
|
|
8905
|
+
"table",
|
|
8906
|
+
"table_row",
|
|
8907
|
+
"table_cell",
|
|
8908
|
+
"text"
|
|
8909
|
+
]).optional(),
|
|
8910
|
+
title: z41.string().optional(),
|
|
8911
|
+
description: z41.string().optional()
|
|
8912
|
+
})).default([]),
|
|
8913
|
+
groups: z41.array(z41.object({
|
|
8914
|
+
kind: z41.enum(ORGANIZABLE_KINDS),
|
|
8915
|
+
title: z41.string(),
|
|
8916
|
+
description: z41.string().optional(),
|
|
8917
|
+
childNodeIds: z41.array(z41.string()).min(1)
|
|
8918
|
+
})).default([])
|
|
8919
|
+
});
|
|
8920
|
+
var SourceBackedValueForPromptSchema = z41.object({
|
|
8921
|
+
value: z41.string(),
|
|
8922
|
+
normalizedValue: z41.string().optional(),
|
|
8923
|
+
confidence: z41.enum(["low", "medium", "high"]).optional(),
|
|
8924
|
+
sourceNodeIds: z41.array(z41.string()).default([]),
|
|
8925
|
+
sourceSpanIds: z41.array(z41.string()).default([])
|
|
8926
|
+
});
|
|
8927
|
+
var OperationalProfilePromptSchema = z41.object({
|
|
8928
|
+
documentType: z41.enum(["policy", "quote"]).optional(),
|
|
8929
|
+
policyTypes: z41.array(z41.string()).optional(),
|
|
8930
|
+
policyNumber: SourceBackedValueForPromptSchema.optional(),
|
|
8931
|
+
namedInsured: SourceBackedValueForPromptSchema.optional(),
|
|
8932
|
+
insurer: SourceBackedValueForPromptSchema.optional(),
|
|
8933
|
+
broker: SourceBackedValueForPromptSchema.optional(),
|
|
8934
|
+
effectiveDate: SourceBackedValueForPromptSchema.optional(),
|
|
8935
|
+
expirationDate: SourceBackedValueForPromptSchema.optional(),
|
|
8936
|
+
retroactiveDate: SourceBackedValueForPromptSchema.optional(),
|
|
8937
|
+
premium: SourceBackedValueForPromptSchema.optional(),
|
|
8938
|
+
coverageTypes: z41.array(z41.string()).optional(),
|
|
8939
|
+
coverages: z41.array(z41.object({
|
|
8940
|
+
name: z41.string(),
|
|
8941
|
+
coverageCode: z41.string().optional(),
|
|
8942
|
+
limit: z41.string().optional(),
|
|
8943
|
+
deductible: z41.string().optional(),
|
|
8944
|
+
premium: z41.string().optional(),
|
|
8945
|
+
formNumber: z41.string().optional(),
|
|
8946
|
+
sectionRef: z41.string().optional(),
|
|
8947
|
+
sourceNodeIds: z41.array(z41.string()).default([]),
|
|
8948
|
+
sourceSpanIds: z41.array(z41.string()).default([])
|
|
8949
|
+
})).optional(),
|
|
8950
|
+
sourceNodeIds: z41.array(z41.string()).optional(),
|
|
8951
|
+
sourceSpanIds: z41.array(z41.string()).optional()
|
|
8952
|
+
});
|
|
8953
|
+
function cleanText(value, fallback) {
|
|
8954
|
+
const text = value?.replace(/\s+/g, " ").trim();
|
|
8955
|
+
return text || fallback;
|
|
8956
|
+
}
|
|
8957
|
+
function compactNode(node) {
|
|
8958
|
+
return {
|
|
8959
|
+
id: node.id,
|
|
8960
|
+
kind: node.kind,
|
|
8961
|
+
title: node.title,
|
|
8962
|
+
path: node.path,
|
|
8963
|
+
pageStart: node.pageStart,
|
|
8964
|
+
pageEnd: node.pageEnd,
|
|
8965
|
+
sourceSpanIds: node.sourceSpanIds.slice(0, 8),
|
|
8966
|
+
text: (node.textExcerpt ?? node.description).slice(0, 700)
|
|
8967
|
+
};
|
|
8968
|
+
}
|
|
8969
|
+
function buildOrganizationPrompt(sourceTree) {
|
|
8970
|
+
const nodes = sourceTree.filter((node) => node.kind !== "table_cell").slice(0, 180).map(compactNode);
|
|
8971
|
+
return `You organize an insurance document source tree.
|
|
8972
|
+
|
|
8973
|
+
Rules:
|
|
8974
|
+
- Use only node IDs from the provided list.
|
|
8975
|
+
- Do not invent text, page numbers, source spans, limits, or policy facts.
|
|
8976
|
+
- 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.
|
|
8977
|
+
- Groups must list existing childNodeIds only.
|
|
8978
|
+
- Keep descriptions short and useful for search.
|
|
8979
|
+
|
|
8980
|
+
Source nodes:
|
|
8981
|
+
${JSON.stringify(nodes, null, 2)}
|
|
8982
|
+
|
|
8983
|
+
Return JSON with labels and groups only.`;
|
|
8984
|
+
}
|
|
8985
|
+
function buildOperationalProfilePrompt(sourceTree, fallback) {
|
|
8986
|
+
const nodes = sourceTree.filter((node) => node.kind !== "document").slice(0, 240).map(compactNode);
|
|
8987
|
+
return `Extract a source-backed operational profile for an insurance policy or quote.
|
|
8988
|
+
|
|
8989
|
+
Return only high-value operational facts needed for policy lists, Q&A, compliance, and certificate generation:
|
|
8990
|
+
- policy number, named insured, insurer/carrier/security, broker/producer, policy period, retroactive date, premium
|
|
8991
|
+
- coverage lines with limits, deductibles, premiums, and form references
|
|
8992
|
+
- coverage type labels
|
|
8993
|
+
|
|
8994
|
+
Rules:
|
|
8995
|
+
- Every returned value must include sourceNodeIds or sourceSpanIds from the provided nodes.
|
|
8996
|
+
- If a value is not directly supported, omit it.
|
|
8997
|
+
- Prefer declarations, schedules, premium tables, and endorsement schedules over generic policy wording.
|
|
8998
|
+
- Do not copy entire policy wording into fields.
|
|
8999
|
+
|
|
9000
|
+
Deterministic baseline:
|
|
9001
|
+
${JSON.stringify(fallback, null, 2)}
|
|
9002
|
+
|
|
9003
|
+
Source nodes:
|
|
9004
|
+
${JSON.stringify(nodes, null, 2)}
|
|
9005
|
+
|
|
9006
|
+
Return JSON for the operational profile.`;
|
|
9007
|
+
}
|
|
9008
|
+
function groupNodeId(documentId, group) {
|
|
9009
|
+
return [
|
|
9010
|
+
documentId.replace(/[^a-zA-Z0-9_.:-]/g, "_"),
|
|
9011
|
+
"source_node",
|
|
9012
|
+
group.kind,
|
|
9013
|
+
group.childNodeIds.join("_").replace(/[^a-zA-Z0-9_.:-]/g, "_").slice(0, 80)
|
|
9014
|
+
].join(":");
|
|
9015
|
+
}
|
|
9016
|
+
function applyOrganization(sourceTree, organization) {
|
|
9017
|
+
const byId = new Map(sourceTree.map((node) => [node.id, node]));
|
|
9018
|
+
let nextTree = sourceTree.map((node) => {
|
|
9019
|
+
const label = organization.labels.find((item) => item.nodeId === node.id);
|
|
9020
|
+
if (!label) return node;
|
|
9021
|
+
return {
|
|
9022
|
+
...node,
|
|
9023
|
+
kind: label.kind ?? node.kind,
|
|
9024
|
+
title: cleanText(label.title, node.title),
|
|
9025
|
+
description: cleanText(label.description, node.description)
|
|
9026
|
+
};
|
|
9027
|
+
});
|
|
9028
|
+
for (const group of organization.groups.slice(0, 40)) {
|
|
9029
|
+
const children = group.childNodeIds.map((id2) => byId.get(id2)).filter((node2) => Boolean(node2));
|
|
9030
|
+
if (children.length === 0) continue;
|
|
9031
|
+
const parentId = children[0].parentId;
|
|
9032
|
+
if (!children.every((child) => child.parentId === parentId)) continue;
|
|
9033
|
+
const documentId = children[0].documentId;
|
|
9034
|
+
const id = groupNodeId(documentId, group);
|
|
9035
|
+
if (byId.has(id)) continue;
|
|
9036
|
+
const sourceSpanIds = [...new Set(children.flatMap((child) => child.sourceSpanIds))];
|
|
9037
|
+
const pageStarts = children.map((child) => child.pageStart).filter((page) => typeof page === "number");
|
|
9038
|
+
const pageEnds = children.map((child) => child.pageEnd ?? child.pageStart).filter((page) => typeof page === "number");
|
|
9039
|
+
const order = Math.min(...children.map((child) => child.order));
|
|
9040
|
+
const node = {
|
|
9041
|
+
id,
|
|
9042
|
+
documentId,
|
|
9043
|
+
parentId,
|
|
9044
|
+
kind: group.kind,
|
|
9045
|
+
title: group.title,
|
|
9046
|
+
description: group.description ?? group.title,
|
|
9047
|
+
textExcerpt: children.map((child) => child.textExcerpt ?? child.description).filter(Boolean).join("\n\n").slice(0, 1600),
|
|
9048
|
+
sourceSpanIds,
|
|
9049
|
+
pageStart: pageStarts.length ? Math.min(...pageStarts) : void 0,
|
|
9050
|
+
pageEnd: pageEnds.length ? Math.max(...pageEnds) : void 0,
|
|
9051
|
+
bbox: children.flatMap((child) => child.bbox ?? []).slice(0, 12),
|
|
9052
|
+
order,
|
|
9053
|
+
path: "",
|
|
9054
|
+
metadata: { sourceTreeVersion: "v3", organizer: "llm_group" }
|
|
9055
|
+
};
|
|
9056
|
+
nextTree = [
|
|
9057
|
+
...nextTree.map(
|
|
9058
|
+
(child) => group.childNodeIds.includes(child.id) ? { ...child, parentId: id, order: child.order + 1e-3 } : child
|
|
9059
|
+
),
|
|
9060
|
+
node
|
|
9061
|
+
];
|
|
9062
|
+
byId.set(id, node);
|
|
9063
|
+
}
|
|
9064
|
+
return normalizeDocumentSourceTreePaths(nextTree);
|
|
9065
|
+
}
|
|
9066
|
+
function sourceTreeToOutline(sourceTree) {
|
|
9067
|
+
const byParent = /* @__PURE__ */ new Map();
|
|
9068
|
+
for (const node of sourceTree.filter((item) => item.kind !== "document")) {
|
|
9069
|
+
const group = byParent.get(node.parentId) ?? [];
|
|
9070
|
+
group.push(node);
|
|
9071
|
+
byParent.set(node.parentId, group);
|
|
9072
|
+
}
|
|
9073
|
+
const root = sourceTree.find((node) => node.kind === "document");
|
|
9074
|
+
const visit = (node) => ({
|
|
9075
|
+
id: node.id,
|
|
9076
|
+
title: node.title,
|
|
9077
|
+
type: node.kind,
|
|
9078
|
+
label: node.kind,
|
|
9079
|
+
pageStart: node.pageStart,
|
|
9080
|
+
pageEnd: node.pageEnd,
|
|
9081
|
+
excerpt: node.textExcerpt,
|
|
9082
|
+
content: node.textExcerpt,
|
|
9083
|
+
sourceSpanIds: node.sourceSpanIds,
|
|
9084
|
+
sourceTextHash: node.sourceSpanIds.join(":") || void 0,
|
|
9085
|
+
interpretationLabels: [node.kind],
|
|
9086
|
+
children: (byParent.get(node.id) ?? []).map(visit)
|
|
9087
|
+
});
|
|
9088
|
+
return (byParent.get(root?.id) ?? []).map(visit);
|
|
9089
|
+
}
|
|
9090
|
+
function valueOf(profile, key) {
|
|
9091
|
+
const value = profile[key];
|
|
9092
|
+
return value && typeof value === "object" && !Array.isArray(value) && "value" in value ? String(value.value) : void 0;
|
|
9093
|
+
}
|
|
9094
|
+
function materializeDocument(params) {
|
|
9095
|
+
const profile = params.operationalProfile;
|
|
9096
|
+
const policyNumber = valueOf(profile, "policyNumber") ?? "Unknown";
|
|
9097
|
+
const insuredName = valueOf(profile, "namedInsured") ?? "Unknown";
|
|
9098
|
+
const carrier = valueOf(profile, "insurer") ?? "Unknown";
|
|
9099
|
+
const effectiveDate = valueOf(profile, "effectiveDate") ?? "Unknown";
|
|
9100
|
+
const expirationDate = valueOf(profile, "expirationDate") ?? "Unknown";
|
|
9101
|
+
const premium = valueOf(profile, "premium");
|
|
9102
|
+
const coverages = profile.coverages.map((coverage) => ({
|
|
9103
|
+
name: coverage.name,
|
|
9104
|
+
coverageCode: coverage.coverageCode,
|
|
9105
|
+
limit: coverage.limit,
|
|
9106
|
+
deductible: coverage.deductible,
|
|
9107
|
+
premium: coverage.premium,
|
|
9108
|
+
formNumber: coverage.formNumber,
|
|
9109
|
+
sectionRef: coverage.sectionRef,
|
|
9110
|
+
sourceSpanIds: coverage.sourceSpanIds,
|
|
9111
|
+
documentNodeId: coverage.sourceNodeIds[0],
|
|
9112
|
+
originalContent: [coverage.name, coverage.limit, coverage.deductible, coverage.premium].filter(Boolean).join(" | ")
|
|
9113
|
+
}));
|
|
9114
|
+
const documentOutline = sourceTreeToOutline(params.sourceTree);
|
|
9115
|
+
const documentMetadata = {
|
|
9116
|
+
sourceTreeVersion: "v3",
|
|
9117
|
+
sourceTreeCanonical: true,
|
|
9118
|
+
tableOfContents: documentOutline.map((node) => ({
|
|
9119
|
+
title: node.title,
|
|
9120
|
+
pageStart: node.pageStart,
|
|
9121
|
+
pageEnd: node.pageEnd,
|
|
9122
|
+
documentNodeId: node.id,
|
|
9123
|
+
sourceSpanIds: node.sourceSpanIds
|
|
9124
|
+
})),
|
|
9125
|
+
agentGuidance: [
|
|
9126
|
+
{
|
|
9127
|
+
kind: "source_tree",
|
|
9128
|
+
title: "Use the source tree as canonical evidence",
|
|
9129
|
+
detail: "Operational fields are projections from source nodes and source spans. Use source nodes for policy wording and exact provenance."
|
|
9130
|
+
}
|
|
9131
|
+
]
|
|
9132
|
+
};
|
|
9133
|
+
const summary = [
|
|
9134
|
+
carrier !== "Unknown" ? carrier : void 0,
|
|
9135
|
+
policyNumber !== "Unknown" ? `#${policyNumber}` : void 0,
|
|
9136
|
+
insuredName !== "Unknown" ? `for ${insuredName}` : void 0,
|
|
9137
|
+
profile.coverageTypes.length ? `covering ${profile.coverageTypes.slice(0, 5).join(", ")}` : void 0
|
|
9138
|
+
].filter(Boolean).join(" ");
|
|
9139
|
+
const base = {
|
|
9140
|
+
id: params.id,
|
|
9141
|
+
type: profile.documentType,
|
|
9142
|
+
carrier,
|
|
9143
|
+
security: carrier,
|
|
9144
|
+
insuredName,
|
|
9145
|
+
premium,
|
|
9146
|
+
policyTypes: profile.policyTypes,
|
|
9147
|
+
coverages,
|
|
9148
|
+
documentMetadata,
|
|
9149
|
+
documentOutline,
|
|
9150
|
+
declarations: {
|
|
9151
|
+
fields: [
|
|
9152
|
+
profile.policyNumber ? { field: "policyNumber", value: profile.policyNumber.value, sourceSpanIds: profile.policyNumber.sourceSpanIds } : void 0,
|
|
9153
|
+
profile.namedInsured ? { field: "namedInsured", value: profile.namedInsured.value, sourceSpanIds: profile.namedInsured.sourceSpanIds } : void 0,
|
|
9154
|
+
profile.insurer ? { field: "insurer", value: profile.insurer.value, sourceSpanIds: profile.insurer.sourceSpanIds } : void 0,
|
|
9155
|
+
profile.effectiveDate ? { field: "policyPeriodStart", value: profile.effectiveDate.value, sourceSpanIds: profile.effectiveDate.sourceSpanIds } : void 0,
|
|
9156
|
+
profile.expirationDate ? { field: "policyPeriodEnd", value: profile.expirationDate.value, sourceSpanIds: profile.expirationDate.sourceSpanIds } : void 0
|
|
9157
|
+
].filter(Boolean)
|
|
9158
|
+
},
|
|
9159
|
+
supplementaryFacts: profile.endorsementSupport.map((item) => ({
|
|
9160
|
+
key: item.kind,
|
|
9161
|
+
value: item.summary,
|
|
9162
|
+
sourceSpanIds: item.sourceSpanIds,
|
|
9163
|
+
documentNodeId: item.sourceNodeIds[0]
|
|
9164
|
+
})),
|
|
9165
|
+
summary: summary || void 0
|
|
9166
|
+
};
|
|
9167
|
+
if (profile.documentType === "quote") {
|
|
9168
|
+
return {
|
|
9169
|
+
...base,
|
|
9170
|
+
type: "quote",
|
|
9171
|
+
quoteNumber: policyNumber,
|
|
9172
|
+
proposedEffectiveDate: effectiveDate === "Unknown" ? void 0 : effectiveDate,
|
|
9173
|
+
proposedExpirationDate: expirationDate === "Unknown" ? void 0 : expirationDate
|
|
9174
|
+
};
|
|
9175
|
+
}
|
|
9176
|
+
return {
|
|
9177
|
+
...base,
|
|
9178
|
+
type: "policy",
|
|
9179
|
+
policyNumber,
|
|
9180
|
+
effectiveDate,
|
|
9181
|
+
expirationDate,
|
|
9182
|
+
retroactiveDate: valueOf(profile, "retroactiveDate")
|
|
9183
|
+
};
|
|
9184
|
+
}
|
|
9185
|
+
async function runSourceTreeExtraction(params) {
|
|
9186
|
+
let sourceTree = buildDocumentSourceTree(params.sourceSpans, params.id);
|
|
9187
|
+
const warnings = [];
|
|
9188
|
+
let modelCalls = 0;
|
|
9189
|
+
let callsWithUsage = 0;
|
|
9190
|
+
let callsMissingUsage = 0;
|
|
9191
|
+
const tokenUsage = { inputTokens: 0, outputTokens: 0 };
|
|
9192
|
+
const performanceReport = { modelCalls: [], totalModelCallDurationMs: 0 };
|
|
9193
|
+
const localTrack = (usage, report) => {
|
|
9194
|
+
modelCalls += 1;
|
|
9195
|
+
if (usage) {
|
|
9196
|
+
callsWithUsage += 1;
|
|
9197
|
+
tokenUsage.inputTokens += usage.inputTokens;
|
|
9198
|
+
tokenUsage.outputTokens += usage.outputTokens;
|
|
9199
|
+
} else {
|
|
9200
|
+
callsMissingUsage += 1;
|
|
9201
|
+
}
|
|
9202
|
+
if (report) {
|
|
9203
|
+
performanceReport.modelCalls.push({ ...report, usage, usageReported: !!usage });
|
|
9204
|
+
if (report.durationMs != null) performanceReport.totalModelCallDurationMs += report.durationMs;
|
|
9205
|
+
}
|
|
9206
|
+
params.trackUsage(usage, report);
|
|
9207
|
+
};
|
|
9208
|
+
try {
|
|
9209
|
+
const budget = params.resolveBudget("extraction_source_tree", 4096);
|
|
9210
|
+
const startedAt = Date.now();
|
|
9211
|
+
const response = await safeGenerateObject(
|
|
9212
|
+
params.generateObject,
|
|
9213
|
+
{
|
|
9214
|
+
prompt: buildOrganizationPrompt(sourceTree),
|
|
9215
|
+
schema: SourceTreeOrganizationSchema,
|
|
9216
|
+
maxTokens: budget.maxTokens,
|
|
9217
|
+
taskKind: "extraction_source_tree",
|
|
9218
|
+
budgetDiagnostics: budget,
|
|
9219
|
+
providerOptions: { ...params.providerOptions, sourceSpans: params.sourceSpans }
|
|
9220
|
+
},
|
|
9221
|
+
{
|
|
9222
|
+
fallback: { labels: [], groups: [] },
|
|
9223
|
+
log: params.log
|
|
9224
|
+
}
|
|
9225
|
+
);
|
|
9226
|
+
localTrack(response.usage, {
|
|
9227
|
+
taskKind: "extraction_source_tree",
|
|
9228
|
+
label: "source_tree_organizer",
|
|
9229
|
+
maxTokens: budget.maxTokens,
|
|
9230
|
+
durationMs: Date.now() - startedAt
|
|
9231
|
+
});
|
|
9232
|
+
sourceTree = applyOrganization(sourceTree, response.object);
|
|
9233
|
+
} catch (error) {
|
|
9234
|
+
warnings.push(`Source-tree organizer failed; deterministic tree used (${error instanceof Error ? error.message : String(error)})`);
|
|
9235
|
+
}
|
|
9236
|
+
const deterministicProfile = buildDeterministicOperationalProfile({
|
|
9237
|
+
sourceTree,
|
|
9238
|
+
sourceSpans: params.sourceSpans
|
|
9239
|
+
});
|
|
9240
|
+
let operationalProfile = deterministicProfile;
|
|
9241
|
+
try {
|
|
9242
|
+
const validNodeIds = new Set(sourceTree.map((node) => node.id));
|
|
9243
|
+
const validSpanIds = new Set(params.sourceSpans.map((span) => span.id));
|
|
9244
|
+
const budget = params.resolveBudget("extraction_operational_profile", 8192);
|
|
9245
|
+
const startedAt = Date.now();
|
|
9246
|
+
const response = await safeGenerateObject(
|
|
9247
|
+
params.generateObject,
|
|
9248
|
+
{
|
|
9249
|
+
prompt: buildOperationalProfilePrompt(sourceTree, deterministicProfile),
|
|
9250
|
+
schema: OperationalProfilePromptSchema,
|
|
9251
|
+
maxTokens: budget.maxTokens,
|
|
9252
|
+
taskKind: "extraction_operational_profile",
|
|
9253
|
+
budgetDiagnostics: budget,
|
|
9254
|
+
providerOptions: { ...params.providerOptions, sourceSpans: params.sourceSpans, sourceTree }
|
|
9255
|
+
},
|
|
9256
|
+
{
|
|
9257
|
+
fallback: deterministicProfile,
|
|
9258
|
+
log: params.log
|
|
9259
|
+
}
|
|
9260
|
+
);
|
|
9261
|
+
localTrack(response.usage, {
|
|
9262
|
+
taskKind: "extraction_operational_profile",
|
|
9263
|
+
label: "operational_profile",
|
|
9264
|
+
maxTokens: budget.maxTokens,
|
|
9265
|
+
durationMs: Date.now() - startedAt
|
|
9266
|
+
});
|
|
9267
|
+
operationalProfile = mergeOperationalProfile(
|
|
9268
|
+
deterministicProfile,
|
|
9269
|
+
response.object,
|
|
9270
|
+
validNodeIds,
|
|
9271
|
+
validSpanIds
|
|
9272
|
+
);
|
|
9273
|
+
} catch (error) {
|
|
9274
|
+
warnings.push(`Operational profile model pass failed; deterministic profile used (${error instanceof Error ? error.message : String(error)})`);
|
|
9275
|
+
}
|
|
9276
|
+
const document = materializeDocument({
|
|
9277
|
+
id: params.id,
|
|
9278
|
+
sourceTree,
|
|
9279
|
+
operationalProfile
|
|
9280
|
+
});
|
|
9281
|
+
return {
|
|
9282
|
+
sourceTree,
|
|
9283
|
+
sourceSpans: params.sourceSpans,
|
|
9284
|
+
sourceChunks: chunkSourceSpans(params.sourceSpans),
|
|
9285
|
+
operationalProfile,
|
|
9286
|
+
document,
|
|
9287
|
+
chunks: [],
|
|
9288
|
+
warnings: [...warnings, ...operationalProfile.warnings],
|
|
9289
|
+
tokenUsage,
|
|
9290
|
+
usageReporting: {
|
|
9291
|
+
modelCalls,
|
|
9292
|
+
callsWithUsage,
|
|
9293
|
+
callsMissingUsage
|
|
9294
|
+
},
|
|
9295
|
+
performanceReport
|
|
9296
|
+
};
|
|
9297
|
+
}
|
|
9298
|
+
|
|
7906
9299
|
// src/extraction/coordinator.ts
|
|
7907
9300
|
function createExtractor(config) {
|
|
7908
9301
|
const {
|
|
@@ -8088,17 +9481,17 @@ ${span.text}` : span.text;
|
|
|
8088
9481
|
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);
|
|
8089
9482
|
return {
|
|
8090
9483
|
sections: candidateSpans.map((span, index) => {
|
|
8091
|
-
const
|
|
8092
|
-
const
|
|
8093
|
-
const title = span.sectionId ?? span.formNumber ?? firstHeadingLine(span.text) ?? `Policy text page ${
|
|
9484
|
+
const pageStart2 = span.pageStart ?? span.location?.startPage ?? span.location?.page ?? startPage;
|
|
9485
|
+
const pageEnd2 = span.pageEnd ?? span.location?.endPage ?? pageStart2;
|
|
9486
|
+
const title = span.sectionId ?? span.formNumber ?? firstHeadingLine(span.text) ?? `Policy text page ${pageStart2}`;
|
|
8094
9487
|
return {
|
|
8095
9488
|
title,
|
|
8096
9489
|
sectionNumber: span.formNumber,
|
|
8097
|
-
pageStart,
|
|
8098
|
-
pageEnd,
|
|
9490
|
+
pageStart: pageStart2,
|
|
9491
|
+
pageEnd: pageEnd2,
|
|
8099
9492
|
type: inferSectionType(title, span.text),
|
|
8100
9493
|
excerpt: span.text.slice(0, 240),
|
|
8101
|
-
recordId: `section_index_${
|
|
9494
|
+
recordId: `section_index_${pageStart2}_${index}`,
|
|
8102
9495
|
sourceSpanIds: [span.id],
|
|
8103
9496
|
sourceTextHash: span.textHash ?? sourceSpanTextHash(span.text)
|
|
8104
9497
|
};
|
|
@@ -8237,6 +9630,51 @@ ${span.text}` : span.text;
|
|
|
8237
9630
|
await sourceStore.addSourceChunks(sourceChunks);
|
|
8238
9631
|
}
|
|
8239
9632
|
}
|
|
9633
|
+
if (sourceSpans.length > 0) {
|
|
9634
|
+
onProgress?.("Building source-native document tree...");
|
|
9635
|
+
const v3 = await runSourceTreeExtraction({
|
|
9636
|
+
id,
|
|
9637
|
+
sourceSpans,
|
|
9638
|
+
generateObject,
|
|
9639
|
+
providerOptions: activeProviderOptions,
|
|
9640
|
+
resolveBudget,
|
|
9641
|
+
trackUsage,
|
|
9642
|
+
log
|
|
9643
|
+
});
|
|
9644
|
+
const reviewReport2 = {
|
|
9645
|
+
issues: v3.warnings.map((warning) => ({
|
|
9646
|
+
code: "source_tree_warning",
|
|
9647
|
+
severity: "warning",
|
|
9648
|
+
message: warning
|
|
9649
|
+
})),
|
|
9650
|
+
rounds: [],
|
|
9651
|
+
artifacts: [
|
|
9652
|
+
{ kind: "source_tree", label: "Source Tree", itemCount: v3.sourceTree.length },
|
|
9653
|
+
{ kind: "source_spans", label: "Source Spans", itemCount: v3.sourceSpans.length },
|
|
9654
|
+
{ kind: "operational_profile", label: "Operational Profile", itemCount: v3.operationalProfile.coverages.length }
|
|
9655
|
+
],
|
|
9656
|
+
reviewRoundRecords: [],
|
|
9657
|
+
formInventory: [],
|
|
9658
|
+
qualityGateStatus: v3.warnings.length > 0 ? "warning" : "passed"
|
|
9659
|
+
};
|
|
9660
|
+
if (shouldFailQualityGate(qualityGate, reviewReport2.qualityGateStatus)) {
|
|
9661
|
+
throw new Error("Extraction quality gate failed. See reviewReport for blocking issues.");
|
|
9662
|
+
}
|
|
9663
|
+
onProgress?.("Source-tree extraction complete.");
|
|
9664
|
+
return {
|
|
9665
|
+
document: v3.document,
|
|
9666
|
+
chunks: [],
|
|
9667
|
+
sourceSpans: v3.sourceSpans,
|
|
9668
|
+
sourceChunks: v3.sourceChunks,
|
|
9669
|
+
sourceTree: v3.sourceTree,
|
|
9670
|
+
operationalProfile: v3.operationalProfile,
|
|
9671
|
+
warnings: v3.warnings,
|
|
9672
|
+
tokenUsage: v3.tokenUsage,
|
|
9673
|
+
usageReporting: v3.usageReporting,
|
|
9674
|
+
performanceReport: v3.performanceReport,
|
|
9675
|
+
reviewReport: reviewReport2
|
|
9676
|
+
};
|
|
9677
|
+
}
|
|
8240
9678
|
const pipelineCtx = createPipelineContext({
|
|
8241
9679
|
id,
|
|
8242
9680
|
onSave: onCheckpointSave,
|
|
@@ -8804,6 +10242,7 @@ ${pageText}`;
|
|
|
8804
10242
|
}));
|
|
8805
10243
|
onProgress?.("Assembling document...");
|
|
8806
10244
|
const document = assembleDocument(id, documentType, memory);
|
|
10245
|
+
attachDocumentStructure({ document, pageAssignments, sourceSpans });
|
|
8807
10246
|
await pipelineCtx.save("assemble", {
|
|
8808
10247
|
id,
|
|
8809
10248
|
pageCount,
|
|
@@ -9106,8 +10545,8 @@ Respond with JSON only:
|
|
|
9106
10545
|
}`;
|
|
9107
10546
|
|
|
9108
10547
|
// src/schemas/application.ts
|
|
9109
|
-
import { z as
|
|
9110
|
-
var FieldTypeSchema =
|
|
10548
|
+
import { z as z42 } from "zod";
|
|
10549
|
+
var FieldTypeSchema = z42.enum([
|
|
9111
10550
|
"text",
|
|
9112
10551
|
"numeric",
|
|
9113
10552
|
"currency",
|
|
@@ -9116,138 +10555,138 @@ var FieldTypeSchema = z41.enum([
|
|
|
9116
10555
|
"table",
|
|
9117
10556
|
"declaration"
|
|
9118
10557
|
]);
|
|
9119
|
-
var ApplicationFieldSchema =
|
|
9120
|
-
id:
|
|
9121
|
-
label:
|
|
9122
|
-
section:
|
|
10558
|
+
var ApplicationFieldSchema = z42.object({
|
|
10559
|
+
id: z42.string(),
|
|
10560
|
+
label: z42.string(),
|
|
10561
|
+
section: z42.string(),
|
|
9123
10562
|
fieldType: FieldTypeSchema,
|
|
9124
|
-
required:
|
|
9125
|
-
options:
|
|
9126
|
-
columns:
|
|
9127
|
-
requiresExplanationIfYes:
|
|
9128
|
-
condition:
|
|
9129
|
-
dependsOn:
|
|
9130
|
-
whenValue:
|
|
10563
|
+
required: z42.boolean(),
|
|
10564
|
+
options: z42.array(z42.string()).optional(),
|
|
10565
|
+
columns: z42.array(z42.string()).optional(),
|
|
10566
|
+
requiresExplanationIfYes: z42.boolean().optional(),
|
|
10567
|
+
condition: z42.object({
|
|
10568
|
+
dependsOn: z42.string(),
|
|
10569
|
+
whenValue: z42.string()
|
|
9131
10570
|
}).optional(),
|
|
9132
|
-
value:
|
|
9133
|
-
source:
|
|
9134
|
-
confidence:
|
|
9135
|
-
sourceSpanIds:
|
|
9136
|
-
userSourceSpanIds:
|
|
9137
|
-
pageNumber:
|
|
9138
|
-
fieldAnchorId:
|
|
9139
|
-
acroFormName:
|
|
9140
|
-
validationStatus:
|
|
9141
|
-
});
|
|
9142
|
-
var ApplicationClassifyResultSchema =
|
|
9143
|
-
isApplication:
|
|
9144
|
-
confidence:
|
|
9145
|
-
applicationType:
|
|
9146
|
-
});
|
|
9147
|
-
var FieldExtractionResultSchema =
|
|
9148
|
-
fields:
|
|
9149
|
-
});
|
|
9150
|
-
var AutoFillMatchSchema =
|
|
9151
|
-
fieldId:
|
|
9152
|
-
value:
|
|
9153
|
-
confidence:
|
|
9154
|
-
contextKey:
|
|
9155
|
-
});
|
|
9156
|
-
var AutoFillResultSchema =
|
|
9157
|
-
matches:
|
|
9158
|
-
});
|
|
9159
|
-
var QuestionBatchResultSchema =
|
|
9160
|
-
batches:
|
|
9161
|
-
});
|
|
9162
|
-
var LookupRequestSchema =
|
|
9163
|
-
type:
|
|
9164
|
-
description:
|
|
9165
|
-
url:
|
|
9166
|
-
targetFieldIds:
|
|
9167
|
-
});
|
|
9168
|
-
var ReplyIntentSchema =
|
|
9169
|
-
primaryIntent:
|
|
9170
|
-
hasAnswers:
|
|
9171
|
-
questionText:
|
|
9172
|
-
questionFieldIds:
|
|
9173
|
-
lookupRequests:
|
|
9174
|
-
});
|
|
9175
|
-
var ParsedAnswerSchema =
|
|
9176
|
-
fieldId:
|
|
9177
|
-
value:
|
|
9178
|
-
explanation:
|
|
9179
|
-
});
|
|
9180
|
-
var AnswerParsingResultSchema =
|
|
9181
|
-
answers:
|
|
9182
|
-
unanswered:
|
|
9183
|
-
});
|
|
9184
|
-
var LookupFillSchema =
|
|
9185
|
-
fieldId:
|
|
9186
|
-
value:
|
|
9187
|
-
source:
|
|
9188
|
-
sourceSpanIds:
|
|
9189
|
-
});
|
|
9190
|
-
var LookupFillResultSchema =
|
|
9191
|
-
fills:
|
|
9192
|
-
unfillable:
|
|
9193
|
-
explanation:
|
|
9194
|
-
});
|
|
9195
|
-
var FlatPdfPlacementSchema =
|
|
9196
|
-
fieldId:
|
|
9197
|
-
page:
|
|
9198
|
-
x:
|
|
9199
|
-
y:
|
|
9200
|
-
text:
|
|
9201
|
-
fontSize:
|
|
9202
|
-
isCheckmark:
|
|
9203
|
-
});
|
|
9204
|
-
var AcroFormMappingSchema =
|
|
9205
|
-
fieldId:
|
|
9206
|
-
acroFormName:
|
|
9207
|
-
value:
|
|
9208
|
-
});
|
|
9209
|
-
var QualityGateStatusSchema =
|
|
9210
|
-
var QualitySeveritySchema =
|
|
9211
|
-
var ApplicationQualityIssueSchema =
|
|
9212
|
-
code:
|
|
10571
|
+
value: z42.string().optional(),
|
|
10572
|
+
source: z42.string().optional().describe("Where the value came from: auto-fill, user, lookup"),
|
|
10573
|
+
confidence: z42.enum(["confirmed", "high", "medium", "low"]).optional(),
|
|
10574
|
+
sourceSpanIds: z42.array(z42.string()).optional().describe("Stable source spans that support the field value or field anchor"),
|
|
10575
|
+
userSourceSpanIds: z42.array(z42.string()).optional().describe("Message or attachment spans that support user-provided values"),
|
|
10576
|
+
pageNumber: z42.number().int().positive().optional().describe("Application page where the field label or anchor appears"),
|
|
10577
|
+
fieldAnchorId: z42.string().optional().describe("Stable field anchor ID derived from page, section, label, and form metadata"),
|
|
10578
|
+
acroFormName: z42.string().optional().describe("Native PDF AcroForm field name when available"),
|
|
10579
|
+
validationStatus: z42.enum(["valid", "needs_review", "unsupported", "missing"]).optional()
|
|
10580
|
+
});
|
|
10581
|
+
var ApplicationClassifyResultSchema = z42.object({
|
|
10582
|
+
isApplication: z42.boolean(),
|
|
10583
|
+
confidence: z42.number().min(0).max(1),
|
|
10584
|
+
applicationType: z42.string().nullable()
|
|
10585
|
+
});
|
|
10586
|
+
var FieldExtractionResultSchema = z42.object({
|
|
10587
|
+
fields: z42.array(ApplicationFieldSchema)
|
|
10588
|
+
});
|
|
10589
|
+
var AutoFillMatchSchema = z42.object({
|
|
10590
|
+
fieldId: z42.string(),
|
|
10591
|
+
value: z42.string(),
|
|
10592
|
+
confidence: z42.enum(["confirmed"]),
|
|
10593
|
+
contextKey: z42.string()
|
|
10594
|
+
});
|
|
10595
|
+
var AutoFillResultSchema = z42.object({
|
|
10596
|
+
matches: z42.array(AutoFillMatchSchema)
|
|
10597
|
+
});
|
|
10598
|
+
var QuestionBatchResultSchema = z42.object({
|
|
10599
|
+
batches: z42.array(z42.array(z42.string()).describe("Array of field IDs in this batch"))
|
|
10600
|
+
});
|
|
10601
|
+
var LookupRequestSchema = z42.object({
|
|
10602
|
+
type: z42.string().describe("Type of lookup: 'records', 'website', 'policy'"),
|
|
10603
|
+
description: z42.string(),
|
|
10604
|
+
url: z42.string().optional(),
|
|
10605
|
+
targetFieldIds: z42.array(z42.string())
|
|
10606
|
+
});
|
|
10607
|
+
var ReplyIntentSchema = z42.object({
|
|
10608
|
+
primaryIntent: z42.enum(["answers_only", "question", "lookup_request", "mixed"]),
|
|
10609
|
+
hasAnswers: z42.boolean(),
|
|
10610
|
+
questionText: z42.string().optional(),
|
|
10611
|
+
questionFieldIds: z42.array(z42.string()).optional(),
|
|
10612
|
+
lookupRequests: z42.array(LookupRequestSchema).optional()
|
|
10613
|
+
});
|
|
10614
|
+
var ParsedAnswerSchema = z42.object({
|
|
10615
|
+
fieldId: z42.string(),
|
|
10616
|
+
value: z42.string(),
|
|
10617
|
+
explanation: z42.string().optional()
|
|
10618
|
+
});
|
|
10619
|
+
var AnswerParsingResultSchema = z42.object({
|
|
10620
|
+
answers: z42.array(ParsedAnswerSchema),
|
|
10621
|
+
unanswered: z42.array(z42.string()).describe("Field IDs that were not answered")
|
|
10622
|
+
});
|
|
10623
|
+
var LookupFillSchema = z42.object({
|
|
10624
|
+
fieldId: z42.string(),
|
|
10625
|
+
value: z42.string(),
|
|
10626
|
+
source: z42.string().describe("Specific citable reference, e.g. 'GL Policy #POL-12345 (Hartford)'"),
|
|
10627
|
+
sourceSpanIds: z42.array(z42.string()).optional()
|
|
10628
|
+
});
|
|
10629
|
+
var LookupFillResultSchema = z42.object({
|
|
10630
|
+
fills: z42.array(LookupFillSchema),
|
|
10631
|
+
unfillable: z42.array(z42.string()),
|
|
10632
|
+
explanation: z42.string().optional()
|
|
10633
|
+
});
|
|
10634
|
+
var FlatPdfPlacementSchema = z42.object({
|
|
10635
|
+
fieldId: z42.string(),
|
|
10636
|
+
page: z42.number(),
|
|
10637
|
+
x: z42.number().describe("Percentage from left edge (0-100)"),
|
|
10638
|
+
y: z42.number().describe("Percentage from top edge (0-100)"),
|
|
10639
|
+
text: z42.string(),
|
|
10640
|
+
fontSize: z42.number().optional(),
|
|
10641
|
+
isCheckmark: z42.boolean().optional()
|
|
10642
|
+
});
|
|
10643
|
+
var AcroFormMappingSchema = z42.object({
|
|
10644
|
+
fieldId: z42.string(),
|
|
10645
|
+
acroFormName: z42.string(),
|
|
10646
|
+
value: z42.string()
|
|
10647
|
+
});
|
|
10648
|
+
var QualityGateStatusSchema = z42.enum(["passed", "warning", "failed"]);
|
|
10649
|
+
var QualitySeveritySchema = z42.enum(["info", "warning", "blocking"]);
|
|
10650
|
+
var ApplicationQualityIssueSchema = z42.object({
|
|
10651
|
+
code: z42.string(),
|
|
9213
10652
|
severity: QualitySeveritySchema,
|
|
9214
|
-
message:
|
|
9215
|
-
fieldId:
|
|
10653
|
+
message: z42.string(),
|
|
10654
|
+
fieldId: z42.string().optional()
|
|
9216
10655
|
});
|
|
9217
|
-
var ApplicationQualityRoundSchema =
|
|
9218
|
-
round:
|
|
9219
|
-
kind:
|
|
10656
|
+
var ApplicationQualityRoundSchema = z42.object({
|
|
10657
|
+
round: z42.number(),
|
|
10658
|
+
kind: z42.string(),
|
|
9220
10659
|
status: QualityGateStatusSchema,
|
|
9221
|
-
summary:
|
|
10660
|
+
summary: z42.string().optional()
|
|
9222
10661
|
});
|
|
9223
|
-
var ApplicationQualityArtifactSchema =
|
|
9224
|
-
kind:
|
|
9225
|
-
label:
|
|
9226
|
-
itemCount:
|
|
10662
|
+
var ApplicationQualityArtifactSchema = z42.object({
|
|
10663
|
+
kind: z42.string(),
|
|
10664
|
+
label: z42.string().optional(),
|
|
10665
|
+
itemCount: z42.number().optional()
|
|
9227
10666
|
});
|
|
9228
|
-
var ApplicationEmailReviewSchema =
|
|
9229
|
-
issues:
|
|
10667
|
+
var ApplicationEmailReviewSchema = z42.object({
|
|
10668
|
+
issues: z42.array(ApplicationQualityIssueSchema),
|
|
9230
10669
|
qualityGateStatus: QualityGateStatusSchema
|
|
9231
10670
|
});
|
|
9232
|
-
var ApplicationQualityReportSchema =
|
|
9233
|
-
issues:
|
|
9234
|
-
rounds:
|
|
9235
|
-
artifacts:
|
|
10671
|
+
var ApplicationQualityReportSchema = z42.object({
|
|
10672
|
+
issues: z42.array(ApplicationQualityIssueSchema),
|
|
10673
|
+
rounds: z42.array(ApplicationQualityRoundSchema).optional(),
|
|
10674
|
+
artifacts: z42.array(ApplicationQualityArtifactSchema).optional(),
|
|
9236
10675
|
emailReview: ApplicationEmailReviewSchema.optional(),
|
|
9237
10676
|
qualityGateStatus: QualityGateStatusSchema
|
|
9238
10677
|
});
|
|
9239
|
-
var ApplicationStateSchema =
|
|
9240
|
-
id:
|
|
9241
|
-
pdfBase64:
|
|
9242
|
-
title:
|
|
9243
|
-
applicationType:
|
|
9244
|
-
fields:
|
|
9245
|
-
batches:
|
|
9246
|
-
currentBatchIndex:
|
|
10678
|
+
var ApplicationStateSchema = z42.object({
|
|
10679
|
+
id: z42.string(),
|
|
10680
|
+
pdfBase64: z42.string().optional().describe("Original PDF, omitted after extraction"),
|
|
10681
|
+
title: z42.string().optional(),
|
|
10682
|
+
applicationType: z42.string().nullable().optional(),
|
|
10683
|
+
fields: z42.array(ApplicationFieldSchema),
|
|
10684
|
+
batches: z42.array(z42.array(z42.string())).optional(),
|
|
10685
|
+
currentBatchIndex: z42.number().default(0),
|
|
9247
10686
|
qualityReport: ApplicationQualityReportSchema.optional(),
|
|
9248
|
-
status:
|
|
9249
|
-
createdAt:
|
|
9250
|
-
updatedAt:
|
|
10687
|
+
status: z42.enum(["classifying", "extracting", "auto_filling", "batching", "collecting", "confirming", "mapping", "complete"]),
|
|
10688
|
+
createdAt: z42.number(),
|
|
10689
|
+
updatedAt: z42.number()
|
|
9251
10690
|
});
|
|
9252
10691
|
|
|
9253
10692
|
// src/application/agents/classifier.ts
|
|
@@ -10602,104 +12041,106 @@ Respond with the final answer, deduplicated citations array, overall confidence
|
|
|
10602
12041
|
}
|
|
10603
12042
|
|
|
10604
12043
|
// src/schemas/query.ts
|
|
10605
|
-
import { z as
|
|
10606
|
-
var QueryIntentSchema =
|
|
12044
|
+
import { z as z43 } from "zod";
|
|
12045
|
+
var QueryIntentSchema = z43.enum([
|
|
10607
12046
|
"policy_question",
|
|
10608
12047
|
"coverage_comparison",
|
|
10609
12048
|
"document_search",
|
|
10610
12049
|
"claims_inquiry",
|
|
10611
12050
|
"general_knowledge"
|
|
10612
12051
|
]);
|
|
10613
|
-
var QueryAttachmentKindSchema =
|
|
10614
|
-
var QueryAttachmentSchema =
|
|
10615
|
-
id:
|
|
12052
|
+
var QueryAttachmentKindSchema = z43.enum(["image", "pdf", "text"]);
|
|
12053
|
+
var QueryAttachmentSchema = z43.object({
|
|
12054
|
+
id: z43.string().optional().describe("Optional stable attachment ID from the caller"),
|
|
10616
12055
|
kind: QueryAttachmentKindSchema,
|
|
10617
|
-
name:
|
|
10618
|
-
mimeType:
|
|
10619
|
-
base64:
|
|
10620
|
-
text:
|
|
10621
|
-
description:
|
|
12056
|
+
name: z43.string().optional().describe("Original filename or user-facing label"),
|
|
12057
|
+
mimeType: z43.string().optional().describe("MIME type such as image/jpeg or application/pdf"),
|
|
12058
|
+
base64: z43.string().optional().describe("Base64-encoded file content for image/pdf attachments"),
|
|
12059
|
+
text: z43.string().optional().describe("Plain-text attachment content when available"),
|
|
12060
|
+
description: z43.string().optional().describe("Caller-provided description of the attachment")
|
|
10622
12061
|
});
|
|
10623
|
-
var QueryRetrievalModeSchema =
|
|
12062
|
+
var QueryRetrievalModeSchema = z43.enum([
|
|
10624
12063
|
"graph_only",
|
|
10625
12064
|
"source_rag",
|
|
10626
12065
|
"long_context",
|
|
10627
12066
|
"hybrid"
|
|
10628
12067
|
]);
|
|
10629
|
-
var SubQuestionSchema =
|
|
10630
|
-
question:
|
|
12068
|
+
var SubQuestionSchema = z43.object({
|
|
12069
|
+
question: z43.string().describe("Atomic sub-question to retrieve and answer independently"),
|
|
10631
12070
|
intent: QueryIntentSchema,
|
|
10632
|
-
chunkTypes:
|
|
10633
|
-
documentFilters:
|
|
10634
|
-
type:
|
|
10635
|
-
carrier:
|
|
10636
|
-
insuredName:
|
|
10637
|
-
policyNumber:
|
|
10638
|
-
quoteNumber:
|
|
10639
|
-
policyTypes:
|
|
12071
|
+
chunkTypes: z43.array(z43.string()).optional().describe("Chunk types to filter retrieval (e.g. coverage, endorsement, declaration)"),
|
|
12072
|
+
documentFilters: z43.object({
|
|
12073
|
+
type: z43.enum(["policy", "quote"]).optional(),
|
|
12074
|
+
carrier: z43.string().optional(),
|
|
12075
|
+
insuredName: z43.string().optional(),
|
|
12076
|
+
policyNumber: z43.string().optional(),
|
|
12077
|
+
quoteNumber: z43.string().optional(),
|
|
12078
|
+
policyTypes: z43.array(PolicyTypeSchema).optional().describe("Filter by policy type (e.g. homeowners_ho3, renters_ho4, pet) to avoid mixing up similar policies")
|
|
10640
12079
|
}).optional().describe("Structured filters to narrow document lookup")
|
|
10641
12080
|
});
|
|
10642
|
-
var QueryClassifyResultSchema =
|
|
12081
|
+
var QueryClassifyResultSchema = z43.object({
|
|
10643
12082
|
intent: QueryIntentSchema,
|
|
10644
|
-
subQuestions:
|
|
10645
|
-
requiresDocumentLookup:
|
|
10646
|
-
requiresChunkSearch:
|
|
10647
|
-
requiresConversationHistory:
|
|
12083
|
+
subQuestions: z43.array(SubQuestionSchema).min(1).describe("Decomposed atomic sub-questions"),
|
|
12084
|
+
requiresDocumentLookup: z43.boolean().describe("Whether structured document lookup is needed"),
|
|
12085
|
+
requiresChunkSearch: z43.boolean().describe("Whether semantic chunk search is needed"),
|
|
12086
|
+
requiresConversationHistory: z43.boolean().describe("Whether conversation history is relevant"),
|
|
10648
12087
|
retrievalMode: QueryRetrievalModeSchema.optional().describe("Preferred retrieval strategy for the query when source-span retrieval is available")
|
|
10649
12088
|
});
|
|
10650
|
-
var EvidenceItemSchema =
|
|
10651
|
-
source:
|
|
10652
|
-
chunkId:
|
|
10653
|
-
|
|
10654
|
-
|
|
10655
|
-
|
|
10656
|
-
|
|
10657
|
-
|
|
10658
|
-
|
|
12089
|
+
var EvidenceItemSchema = z43.object({
|
|
12090
|
+
source: z43.enum(["chunk", "document", "conversation", "attachment", "source_span", "source_node"]),
|
|
12091
|
+
chunkId: z43.string().optional(),
|
|
12092
|
+
sourceNodeId: z43.string().optional(),
|
|
12093
|
+
sourceSpanId: z43.string().optional(),
|
|
12094
|
+
documentId: z43.string().optional(),
|
|
12095
|
+
turnId: z43.string().optional(),
|
|
12096
|
+
attachmentId: z43.string().optional(),
|
|
12097
|
+
text: z43.string().describe("Text excerpt from the source"),
|
|
12098
|
+
relevance: z43.number().min(0).max(1),
|
|
10659
12099
|
retrievalMode: QueryRetrievalModeSchema.optional(),
|
|
10660
12100
|
sourceLocation: SourceSpanLocationSchema.optional(),
|
|
10661
|
-
metadata:
|
|
10662
|
-
});
|
|
10663
|
-
var AttachmentInterpretationSchema =
|
|
10664
|
-
summary:
|
|
10665
|
-
extractedFacts:
|
|
10666
|
-
recommendedFocus:
|
|
10667
|
-
confidence:
|
|
10668
|
-
});
|
|
10669
|
-
var RetrievalResultSchema =
|
|
10670
|
-
subQuestion:
|
|
10671
|
-
evidence:
|
|
10672
|
-
});
|
|
10673
|
-
var CitationSchema =
|
|
10674
|
-
index:
|
|
10675
|
-
chunkId:
|
|
10676
|
-
|
|
10677
|
-
|
|
10678
|
-
|
|
10679
|
-
|
|
10680
|
-
|
|
10681
|
-
|
|
12101
|
+
metadata: z43.array(z43.object({ key: z43.string(), value: z43.string() })).optional()
|
|
12102
|
+
});
|
|
12103
|
+
var AttachmentInterpretationSchema = z43.object({
|
|
12104
|
+
summary: z43.string().describe("Concise summary of what the attachment shows or contains"),
|
|
12105
|
+
extractedFacts: z43.array(z43.string()).describe("Specific observable or document facts grounded in the attachment"),
|
|
12106
|
+
recommendedFocus: z43.array(z43.string()).describe("Important details to incorporate when answering follow-up questions"),
|
|
12107
|
+
confidence: z43.number().min(0).max(1)
|
|
12108
|
+
});
|
|
12109
|
+
var RetrievalResultSchema = z43.object({
|
|
12110
|
+
subQuestion: z43.string(),
|
|
12111
|
+
evidence: z43.array(EvidenceItemSchema)
|
|
12112
|
+
});
|
|
12113
|
+
var CitationSchema = z43.object({
|
|
12114
|
+
index: z43.number().describe("Citation number [1], [2], etc."),
|
|
12115
|
+
chunkId: z43.string().optional().describe("Source chunk ID, e.g. doc-123:coverage:2"),
|
|
12116
|
+
sourceNodeId: z43.string().optional().describe("Source tree node ID when available"),
|
|
12117
|
+
sourceSpanId: z43.string().optional().describe("Precise source span ID when available"),
|
|
12118
|
+
documentId: z43.string(),
|
|
12119
|
+
documentType: z43.enum(["policy", "quote"]).optional(),
|
|
12120
|
+
field: z43.string().optional().describe("Specific field path, e.g. coverages[0].deductible"),
|
|
12121
|
+
quote: z43.string().describe("Exact text from source that supports the claim"),
|
|
12122
|
+
relevance: z43.number().min(0).max(1),
|
|
10682
12123
|
retrievalMode: QueryRetrievalModeSchema.optional(),
|
|
10683
12124
|
sourceLocation: SourceSpanLocationSchema.optional()
|
|
10684
12125
|
});
|
|
10685
|
-
var SubAnswerSchema =
|
|
10686
|
-
subQuestion:
|
|
10687
|
-
answer:
|
|
10688
|
-
citations:
|
|
10689
|
-
confidence:
|
|
10690
|
-
needsMoreContext:
|
|
10691
|
-
});
|
|
10692
|
-
var VerifyResultSchema =
|
|
10693
|
-
approved:
|
|
10694
|
-
issues:
|
|
10695
|
-
retrySubQuestions:
|
|
10696
|
-
});
|
|
10697
|
-
var QueryResultSchema =
|
|
10698
|
-
answer:
|
|
10699
|
-
citations:
|
|
12126
|
+
var SubAnswerSchema = z43.object({
|
|
12127
|
+
subQuestion: z43.string(),
|
|
12128
|
+
answer: z43.string(),
|
|
12129
|
+
citations: z43.array(CitationSchema),
|
|
12130
|
+
confidence: z43.number().min(0).max(1),
|
|
12131
|
+
needsMoreContext: z43.boolean().describe("True if evidence was insufficient to answer fully")
|
|
12132
|
+
});
|
|
12133
|
+
var VerifyResultSchema = z43.object({
|
|
12134
|
+
approved: z43.boolean().describe("Whether all sub-answers are adequately grounded"),
|
|
12135
|
+
issues: z43.array(z43.string()).describe("Specific grounding or consistency issues found"),
|
|
12136
|
+
retrySubQuestions: z43.array(z43.string()).optional().describe("Sub-questions that need additional retrieval or re-reasoning")
|
|
12137
|
+
});
|
|
12138
|
+
var QueryResultSchema = z43.object({
|
|
12139
|
+
answer: z43.string(),
|
|
12140
|
+
citations: z43.array(CitationSchema),
|
|
10700
12141
|
intent: QueryIntentSchema,
|
|
10701
|
-
confidence:
|
|
10702
|
-
followUp:
|
|
12142
|
+
confidence: z43.number().min(0).max(1),
|
|
12143
|
+
followUp: z43.string().optional().describe("Suggested follow-up question if applicable")
|
|
10703
12144
|
});
|
|
10704
12145
|
|
|
10705
12146
|
// src/query/retriever.ts
|
|
@@ -10714,6 +12155,35 @@ async function retrieve(subQuestion, conversationId, config) {
|
|
|
10714
12155
|
tasks.push(
|
|
10715
12156
|
(async () => {
|
|
10716
12157
|
try {
|
|
12158
|
+
const nodeResults = await sourceRetriever?.searchSourceNodes?.({
|
|
12159
|
+
question: subQuestion.question,
|
|
12160
|
+
limit: retrievalLimit,
|
|
12161
|
+
mode: retrievalMode
|
|
12162
|
+
}) ?? [];
|
|
12163
|
+
for (const result of nodeResults) {
|
|
12164
|
+
const hierarchyText = result.hierarchy.map((node) => `${node.path} ${node.title}: ${node.textExcerpt ?? node.description}`).join("\n");
|
|
12165
|
+
const spanText = result.spans.map((span) => `[source-span:${span.id}${span.pageStart ? ` p.${span.pageStart}` : ""}]
|
|
12166
|
+
${span.text}`).join("\n\n");
|
|
12167
|
+
evidence.push({
|
|
12168
|
+
source: "source_node",
|
|
12169
|
+
sourceNodeId: result.node.id,
|
|
12170
|
+
sourceSpanId: result.spans[0]?.id,
|
|
12171
|
+
documentId: result.node.documentId,
|
|
12172
|
+
text: [hierarchyText, spanText].filter(Boolean).join("\n\n"),
|
|
12173
|
+
relevance: result.relevance,
|
|
12174
|
+
retrievalMode,
|
|
12175
|
+
sourceLocation: result.spans[0]?.location ?? (result.node.pageStart ? { page: result.node.pageStart } : void 0),
|
|
12176
|
+
metadata: [
|
|
12177
|
+
{ key: "kind", value: result.node.kind },
|
|
12178
|
+
{ key: "path", value: result.node.path },
|
|
12179
|
+
{ key: "title", value: result.node.title },
|
|
12180
|
+
...result.node.metadata ? recordToKVArray(Object.fromEntries(
|
|
12181
|
+
Object.entries(result.node.metadata).filter(([, value]) => typeof value === "string").map(([key, value]) => [key, value])
|
|
12182
|
+
)) : []
|
|
12183
|
+
]
|
|
12184
|
+
});
|
|
12185
|
+
}
|
|
12186
|
+
if (nodeResults.length > 0) return;
|
|
10717
12187
|
const sourceResults = await sourceRetriever?.searchSourceSpans({
|
|
10718
12188
|
question: subQuestion.question,
|
|
10719
12189
|
limit: retrievalLimit,
|
|
@@ -10733,7 +12203,7 @@ async function retrieve(subQuestion, conversationId, config) {
|
|
|
10733
12203
|
});
|
|
10734
12204
|
}
|
|
10735
12205
|
} catch (e) {
|
|
10736
|
-
await log?.(`Source
|
|
12206
|
+
await log?.(`Source tree search failed for "${subQuestion.question}": ${e}`);
|
|
10737
12207
|
}
|
|
10738
12208
|
})()
|
|
10739
12209
|
);
|
|
@@ -10935,7 +12405,7 @@ Answer the sub-question based on the evidence above. For every factual claim, in
|
|
|
10935
12405
|
async function reason(subQuestion, intent, evidence, config) {
|
|
10936
12406
|
const { generateObject, providerOptions } = config;
|
|
10937
12407
|
const evidenceText = evidence.map((e, i) => {
|
|
10938
|
-
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}]`;
|
|
12408
|
+
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}]`;
|
|
10939
12409
|
return `Evidence ${i + 1} ${sourceLabel} (relevance: ${e.relevance.toFixed(2)}):
|
|
10940
12410
|
${e.text}`;
|
|
10941
12411
|
}).join("\n\n");
|
|
@@ -11737,7 +13207,7 @@ ${sa.answer}`).join("\n\n"),
|
|
|
11737
13207
|
}
|
|
11738
13208
|
|
|
11739
13209
|
// src/pce/index.ts
|
|
11740
|
-
import { z as
|
|
13210
|
+
import { z as z44 } from "zod";
|
|
11741
13211
|
|
|
11742
13212
|
// src/prompts/pce/index.ts
|
|
11743
13213
|
function buildPceNormalizePrompt(input) {
|
|
@@ -11771,11 +13241,11 @@ ${input.openQuestions.map((question) => `- ${question.id}${question.fieldPath ?
|
|
|
11771
13241
|
}
|
|
11772
13242
|
|
|
11773
13243
|
// src/pce/index.ts
|
|
11774
|
-
var ReplyAnswersSchema =
|
|
11775
|
-
answers:
|
|
11776
|
-
questionId:
|
|
11777
|
-
fieldPath:
|
|
11778
|
-
answer:
|
|
13244
|
+
var ReplyAnswersSchema = z44.object({
|
|
13245
|
+
answers: z44.array(z44.object({
|
|
13246
|
+
questionId: z44.string().optional(),
|
|
13247
|
+
fieldPath: z44.string().optional(),
|
|
13248
|
+
answer: z44.string()
|
|
11779
13249
|
}))
|
|
11780
13250
|
});
|
|
11781
13251
|
function createPceAgent(config = {}) {
|
|
@@ -12601,6 +14071,13 @@ export {
|
|
|
12601
14071
|
DeductibleTypeSchema,
|
|
12602
14072
|
DefenseCostTreatmentSchema,
|
|
12603
14073
|
DefinitionSchema,
|
|
14074
|
+
DocumentAgentGuidanceSchema,
|
|
14075
|
+
DocumentMetadataSchema,
|
|
14076
|
+
DocumentNodeSchema,
|
|
14077
|
+
DocumentPageMapEntrySchema,
|
|
14078
|
+
DocumentSourceNodeKindSchema,
|
|
14079
|
+
DocumentSourceNodeSchema,
|
|
14080
|
+
DocumentTableOfContentsEntrySchema,
|
|
12604
14081
|
DocumentTypeSchema,
|
|
12605
14082
|
DriverRecordSchema,
|
|
12606
14083
|
DwellingDetailsSchema,
|
|
@@ -12655,6 +14132,9 @@ export {
|
|
|
12655
14132
|
MemorySourceStore,
|
|
12656
14133
|
MissingInfoQuestionSchema,
|
|
12657
14134
|
NamedInsuredSchema,
|
|
14135
|
+
OperationalCoverageLineSchema,
|
|
14136
|
+
OperationalEndorsementSupportSchema,
|
|
14137
|
+
OperationalPartySchema,
|
|
12658
14138
|
PERSONAL_AUTO_USAGES,
|
|
12659
14139
|
PET_SPECIES,
|
|
12660
14140
|
PLATFORM_CONFIGS,
|
|
@@ -12684,6 +14164,7 @@ export {
|
|
|
12684
14164
|
PolicyChangeStatusSchema,
|
|
12685
14165
|
PolicyConditionSchema,
|
|
12686
14166
|
PolicyDocumentSchema,
|
|
14167
|
+
PolicyOperationalProfileSchema,
|
|
12687
14168
|
PolicySectionTypeSchema,
|
|
12688
14169
|
PolicyTermTypeSchema,
|
|
12689
14170
|
PolicyTypeSchema,
|
|
@@ -12715,6 +14196,7 @@ export {
|
|
|
12715
14196
|
ScheduledItemCategorySchema,
|
|
12716
14197
|
SectionSchema,
|
|
12717
14198
|
SharedLimitSchema,
|
|
14199
|
+
SourceBackedValueSchema,
|
|
12718
14200
|
SourceChunkSchema,
|
|
12719
14201
|
SourceKindSchema,
|
|
12720
14202
|
SourceSpanBBoxSchema,
|
|
@@ -12756,7 +14238,9 @@ export {
|
|
|
12756
14238
|
buildConfirmationSummaryPrompt,
|
|
12757
14239
|
buildConversationMemoryGuidance,
|
|
12758
14240
|
buildCoverageGapPrompt,
|
|
14241
|
+
buildDeterministicOperationalProfile,
|
|
12759
14242
|
buildDoclingProviderOptions,
|
|
14243
|
+
buildDocumentSourceTree,
|
|
12760
14244
|
buildFieldExplanationPrompt,
|
|
12761
14245
|
buildFieldExtractionPrompt,
|
|
12762
14246
|
buildFlatPdfMappingPrompt,
|
|
@@ -12805,9 +14289,11 @@ export {
|
|
|
12805
14289
|
getTemplate,
|
|
12806
14290
|
isDoclingExtractionInput,
|
|
12807
14291
|
isFileReference,
|
|
14292
|
+
mergeOperationalProfile,
|
|
12808
14293
|
mergeQuestionAnswers,
|
|
12809
14294
|
mergeSourceSpans,
|
|
12810
14295
|
normalizeDoclingDocument,
|
|
14296
|
+
normalizeDocumentSourceTreePaths,
|
|
12811
14297
|
normalizeForMatch,
|
|
12812
14298
|
orderSourceEvidence,
|
|
12813
14299
|
overlayTextOnPdf,
|