@claritylabs/cl-sdk 1.3.3 → 1.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +176 -0
- package/dist/index.d.ts +176 -0
- package/dist/index.js +67 -639
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +67 -639
- package/dist/index.mjs.map +1 -1
- package/dist/storage-sqlite.d.mts +79 -0
- package/dist/storage-sqlite.d.ts +79 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -908,6 +908,7 @@ var FormReferenceSchema = import_zod3.z.object({
|
|
|
908
908
|
var TaxFeeItemSchema = import_zod3.z.object({
|
|
909
909
|
name: import_zod3.z.string(),
|
|
910
910
|
amount: import_zod3.z.string(),
|
|
911
|
+
amountValue: import_zod3.z.number().optional(),
|
|
911
912
|
type: import_zod3.z.enum(["tax", "fee", "surcharge", "assessment"]).optional(),
|
|
912
913
|
description: import_zod3.z.string().optional()
|
|
913
914
|
});
|
|
@@ -952,9 +953,11 @@ var CoverageValueTypeSchema = import_zod4.z.enum([
|
|
|
952
953
|
var CoverageSchema = import_zod4.z.object({
|
|
953
954
|
name: import_zod4.z.string(),
|
|
954
955
|
limit: import_zod4.z.string(),
|
|
956
|
+
limitAmount: import_zod4.z.number().optional(),
|
|
955
957
|
limitType: LimitTypeSchema.optional(),
|
|
956
958
|
limitValueType: CoverageValueTypeSchema.optional(),
|
|
957
959
|
deductible: import_zod4.z.string().optional(),
|
|
960
|
+
deductibleAmount: import_zod4.z.number().optional(),
|
|
958
961
|
deductibleValueType: CoverageValueTypeSchema.optional(),
|
|
959
962
|
formNumber: import_zod4.z.string().optional(),
|
|
960
963
|
pageNumber: import_zod4.z.number().optional(),
|
|
@@ -970,9 +973,11 @@ var EnrichedCoverageSchema = import_zod4.z.object({
|
|
|
970
973
|
formNumber: import_zod4.z.string().optional(),
|
|
971
974
|
formEditionDate: import_zod4.z.string().optional(),
|
|
972
975
|
limit: import_zod4.z.string(),
|
|
976
|
+
limitAmount: import_zod4.z.number().optional(),
|
|
973
977
|
limitType: LimitTypeSchema.optional(),
|
|
974
978
|
limitValueType: CoverageValueTypeSchema.optional(),
|
|
975
979
|
deductible: import_zod4.z.string().optional(),
|
|
980
|
+
deductibleAmount: import_zod4.z.number().optional(),
|
|
976
981
|
deductibleType: DeductibleTypeSchema.optional(),
|
|
977
982
|
deductibleValueType: CoverageValueTypeSchema.optional(),
|
|
978
983
|
sir: import_zod4.z.string().optional(),
|
|
@@ -1653,7 +1658,8 @@ var UnderwritingConditionSchema = import_zod16.z.object({
|
|
|
1653
1658
|
});
|
|
1654
1659
|
var PremiumLineSchema = import_zod16.z.object({
|
|
1655
1660
|
line: import_zod16.z.string(),
|
|
1656
|
-
amount: import_zod16.z.string()
|
|
1661
|
+
amount: import_zod16.z.string(),
|
|
1662
|
+
amountValue: import_zod16.z.number().optional()
|
|
1657
1663
|
});
|
|
1658
1664
|
var AuxiliaryFactSchema = import_zod16.z.object({
|
|
1659
1665
|
key: import_zod16.z.string(),
|
|
@@ -1696,6 +1702,7 @@ var BaseDocumentFields = {
|
|
|
1696
1702
|
security: import_zod16.z.string().optional(),
|
|
1697
1703
|
insuredName: import_zod16.z.string(),
|
|
1698
1704
|
premium: import_zod16.z.string().optional(),
|
|
1705
|
+
premiumAmount: import_zod16.z.number().optional(),
|
|
1699
1706
|
summary: import_zod16.z.string().optional(),
|
|
1700
1707
|
policyTypes: import_zod16.z.array(import_zod16.z.string()).optional(),
|
|
1701
1708
|
coverages: import_zod16.z.array(CoverageSchema),
|
|
@@ -1747,8 +1754,11 @@ var BaseDocumentFields = {
|
|
|
1747
1754
|
mortgageHolders: import_zod16.z.array(EndorsementPartySchema).optional(),
|
|
1748
1755
|
taxesAndFees: import_zod16.z.array(TaxFeeItemSchema).optional(),
|
|
1749
1756
|
totalCost: import_zod16.z.string().optional(),
|
|
1757
|
+
totalCostAmount: import_zod16.z.number().optional(),
|
|
1750
1758
|
minimumPremium: import_zod16.z.string().optional(),
|
|
1759
|
+
minimumPremiumAmount: import_zod16.z.number().optional(),
|
|
1751
1760
|
depositPremium: import_zod16.z.string().optional(),
|
|
1761
|
+
depositPremiumAmount: import_zod16.z.number().optional(),
|
|
1752
1762
|
paymentPlan: PaymentPlanSchema.optional(),
|
|
1753
1763
|
auditType: AuditTypeSchema.optional(),
|
|
1754
1764
|
ratingBasis: import_zod16.z.array(RatingBasisSchema).optional(),
|
|
@@ -3214,21 +3224,6 @@ function getCoveredReasons(memory) {
|
|
|
3214
3224
|
}
|
|
3215
3225
|
|
|
3216
3226
|
// src/extraction/promote.ts
|
|
3217
|
-
function getDeclarationFields(doc) {
|
|
3218
|
-
const decl = doc.declarations;
|
|
3219
|
-
return Array.isArray(decl?.fields) ? decl.fields : [];
|
|
3220
|
-
}
|
|
3221
|
-
function fieldMatches(fieldName, patterns) {
|
|
3222
|
-
const lower = normalizeFieldName(fieldName);
|
|
3223
|
-
return patterns.some((p) => lower === normalizeFieldName(p));
|
|
3224
|
-
}
|
|
3225
|
-
function normalizeFieldName(fieldName) {
|
|
3226
|
-
return fieldName.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
3227
|
-
}
|
|
3228
|
-
function findFieldValue(fields, patterns, reject) {
|
|
3229
|
-
const match = fields.find((f) => fieldMatches(f.field, patterns) && !reject?.(f));
|
|
3230
|
-
return match?.value;
|
|
3231
|
-
}
|
|
3232
3227
|
function stringValue(value) {
|
|
3233
3228
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
3234
3229
|
}
|
|
@@ -3247,14 +3242,6 @@ function promoteRawFields(raw, mappings) {
|
|
|
3247
3242
|
delete raw[from];
|
|
3248
3243
|
}
|
|
3249
3244
|
}
|
|
3250
|
-
function findRawOrDeclarationValue(raw, fields, lookup) {
|
|
3251
|
-
return (lookup.rawKey ? raw[lookup.rawKey] : void 0) || findFieldValue(fields, lookup.patterns, lookup.reject);
|
|
3252
|
-
}
|
|
3253
|
-
function promoteRawOrDeclarationString(raw, fields, targetKey, rawKeys, lookup) {
|
|
3254
|
-
if (raw[targetKey]) return;
|
|
3255
|
-
const value = findRawString(raw, rawKeys) ?? findFieldValue(fields, lookup.patterns, lookup.reject);
|
|
3256
|
-
if (value) raw[targetKey] = value;
|
|
3257
|
-
}
|
|
3258
3245
|
function promoteCarrierFields(doc) {
|
|
3259
3246
|
const raw = doc;
|
|
3260
3247
|
promoteRawFields(raw, [
|
|
@@ -3271,55 +3258,14 @@ function promoteCarrierFields(doc) {
|
|
|
3271
3258
|
};
|
|
3272
3259
|
}
|
|
3273
3260
|
}
|
|
3274
|
-
var BROKER_NAME_PATTERNS = [
|
|
3275
|
-
"brokerName",
|
|
3276
|
-
"broker",
|
|
3277
|
-
"agentName",
|
|
3278
|
-
"agent",
|
|
3279
|
-
"producerName",
|
|
3280
|
-
"producerAgency",
|
|
3281
|
-
"agencyName",
|
|
3282
|
-
"brokerAgency"
|
|
3283
|
-
];
|
|
3284
|
-
var BROKER_CONTACT_PATTERNS = [
|
|
3285
|
-
"brokerContactName",
|
|
3286
|
-
"brokerContact",
|
|
3287
|
-
"agentContactName",
|
|
3288
|
-
"producerContactName",
|
|
3289
|
-
"producerContact"
|
|
3290
|
-
];
|
|
3291
|
-
var BROKER_LICENSE_PATTERNS = [
|
|
3292
|
-
"brokerLicenseNumber",
|
|
3293
|
-
"brokerNumber",
|
|
3294
|
-
"agentLicenseNumber",
|
|
3295
|
-
"producerLicenseNumber",
|
|
3296
|
-
"producerNumber",
|
|
3297
|
-
"agentNumber"
|
|
3298
|
-
];
|
|
3299
|
-
var BROKER_PHONE_PATTERNS = ["brokerPhone", "agentPhone", "producerPhone"];
|
|
3300
|
-
var BROKER_EMAIL_PATTERNS = ["brokerEmail", "agentEmail", "producerEmail"];
|
|
3301
|
-
var BROKER_ADDRESS_PATTERNS = ["brokerAddress", "agentAddress", "producerAddress"];
|
|
3302
3261
|
function promoteBroker(doc) {
|
|
3303
3262
|
const raw = doc;
|
|
3304
|
-
const
|
|
3305
|
-
const
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
const
|
|
3310
|
-
rawKey: "brokerContactName",
|
|
3311
|
-
patterns: BROKER_CONTACT_PATTERNS
|
|
3312
|
-
});
|
|
3313
|
-
const brokerLicense = findRawOrDeclarationValue(raw, fields, {
|
|
3314
|
-
rawKey: "brokerLicenseNumber",
|
|
3315
|
-
patterns: BROKER_LICENSE_PATTERNS
|
|
3316
|
-
});
|
|
3317
|
-
const brokerPhone = findRawOrDeclarationValue(raw, fields, { patterns: BROKER_PHONE_PATTERNS });
|
|
3318
|
-
const brokerEmail = findRawOrDeclarationValue(raw, fields, { patterns: BROKER_EMAIL_PATTERNS });
|
|
3319
|
-
const brokerAddress = findRawOrDeclarationValue(raw, fields, { patterns: BROKER_ADDRESS_PATTERNS });
|
|
3320
|
-
if (brokerAgency) raw.brokerAgency = brokerAgency;
|
|
3321
|
-
if (brokerContact) raw.brokerContactName = brokerContact;
|
|
3322
|
-
if (brokerLicense) raw.brokerLicenseNumber = brokerLicense;
|
|
3263
|
+
const brokerAgency = findRawString(raw, ["brokerAgency"]);
|
|
3264
|
+
const brokerContact = findRawString(raw, ["brokerContactName"]);
|
|
3265
|
+
const brokerLicense = findRawString(raw, ["brokerLicenseNumber"]);
|
|
3266
|
+
const brokerPhone = findRawString(raw, ["brokerPhone"]);
|
|
3267
|
+
const brokerEmail = findRawString(raw, ["brokerEmail"]);
|
|
3268
|
+
const brokerAddress = findRawString(raw, ["brokerAddress"]);
|
|
3323
3269
|
if (!raw.producer && brokerAgency) {
|
|
3324
3270
|
raw.producer = {
|
|
3325
3271
|
agencyName: brokerAgency,
|
|
@@ -3331,421 +3277,9 @@ function promoteBroker(doc) {
|
|
|
3331
3277
|
};
|
|
3332
3278
|
}
|
|
3333
3279
|
}
|
|
3334
|
-
var LOSS_PAYEE_NAME_PATTERNS = [
|
|
3335
|
-
"lossPayeeName",
|
|
3336
|
-
"lossPayee",
|
|
3337
|
-
"lossPayeeHolder"
|
|
3338
|
-
];
|
|
3339
|
-
var LOSS_PAYEE_ADDRESS_PATTERNS = ["lossPayeeAddress"];
|
|
3340
|
-
var MORTGAGE_HOLDER_NAME_PATTERNS = [
|
|
3341
|
-
"mortgagee",
|
|
3342
|
-
"mortgageHolder",
|
|
3343
|
-
"mortgageHolderName",
|
|
3344
|
-
"mortgageeName",
|
|
3345
|
-
"lienholder",
|
|
3346
|
-
"lienholderName"
|
|
3347
|
-
];
|
|
3348
|
-
var MORTGAGE_HOLDER_ADDRESS_PATTERNS = [
|
|
3349
|
-
"mortgageeAddress",
|
|
3350
|
-
"mortgageHolderAddress",
|
|
3351
|
-
"lienholderAddress"
|
|
3352
|
-
];
|
|
3353
|
-
function promoteLossPayees(doc) {
|
|
3354
|
-
const raw = doc;
|
|
3355
|
-
const fields = getDeclarationFields(doc);
|
|
3356
|
-
if (!raw.lossPayees || Array.isArray(raw.lossPayees) && raw.lossPayees.length === 0) {
|
|
3357
|
-
const name = findFieldValue(fields, LOSS_PAYEE_NAME_PATTERNS);
|
|
3358
|
-
if (name) {
|
|
3359
|
-
const address = findFieldValue(fields, LOSS_PAYEE_ADDRESS_PATTERNS);
|
|
3360
|
-
raw.lossPayees = [{
|
|
3361
|
-
name,
|
|
3362
|
-
role: "loss_payee",
|
|
3363
|
-
...address ? { address: { street1: address } } : {}
|
|
3364
|
-
}];
|
|
3365
|
-
}
|
|
3366
|
-
}
|
|
3367
|
-
if (!raw.mortgageHolders || Array.isArray(raw.mortgageHolders) && raw.mortgageHolders.length === 0) {
|
|
3368
|
-
const name = findFieldValue(fields, MORTGAGE_HOLDER_NAME_PATTERNS);
|
|
3369
|
-
if (name) {
|
|
3370
|
-
const address = findFieldValue(fields, MORTGAGE_HOLDER_ADDRESS_PATTERNS);
|
|
3371
|
-
raw.mortgageHolders = [{
|
|
3372
|
-
name,
|
|
3373
|
-
role: "mortgage_holder",
|
|
3374
|
-
...address ? { address: { street1: address } } : {}
|
|
3375
|
-
}];
|
|
3376
|
-
}
|
|
3377
|
-
}
|
|
3378
|
-
}
|
|
3379
|
-
function promoteLocations(doc) {
|
|
3380
|
-
const raw = doc;
|
|
3381
|
-
if (Array.isArray(raw.locations) && raw.locations.length > 0) return;
|
|
3382
|
-
const fields = getDeclarationFields(doc);
|
|
3383
|
-
if (fields.length === 0) return;
|
|
3384
|
-
const locationGroups = /* @__PURE__ */ new Map();
|
|
3385
|
-
for (const f of fields) {
|
|
3386
|
-
const lower = f.field.toLowerCase().replace(/[\s_-]/g, "");
|
|
3387
|
-
if (lower.includes("locationnumber") || lower.includes("locnumber") || lower.includes("locno")) {
|
|
3388
|
-
const key = f.value;
|
|
3389
|
-
if (!locationGroups.has(key)) locationGroups.set(key, /* @__PURE__ */ new Map());
|
|
3390
|
-
locationGroups.get(key).set("number", f.value);
|
|
3391
|
-
continue;
|
|
3392
|
-
}
|
|
3393
|
-
if (lower.includes("buildingnumber") || lower.includes("bldgnumber") || lower.includes("bldgno")) {
|
|
3394
|
-
const lastKey2 = [...locationGroups.keys()].pop();
|
|
3395
|
-
if (lastKey2) locationGroups.get(lastKey2).set("buildingNumber", f.value);
|
|
3396
|
-
continue;
|
|
3397
|
-
}
|
|
3398
|
-
const section = (f.section ?? "").toLowerCase();
|
|
3399
|
-
const isLocationField = section.includes("location") || section.includes("building") || section.includes("premises") || section.includes("schedule of locations");
|
|
3400
|
-
if (!isLocationField) continue;
|
|
3401
|
-
if (locationGroups.size === 0) {
|
|
3402
|
-
locationGroups.set("1", /* @__PURE__ */ new Map([["number", "1"]]));
|
|
3403
|
-
}
|
|
3404
|
-
const lastKey = [...locationGroups.keys()].pop();
|
|
3405
|
-
const group = locationGroups.get(lastKey);
|
|
3406
|
-
if (lower.includes("construction") || lower.includes("constructiontype")) {
|
|
3407
|
-
group.set("constructionType", f.value);
|
|
3408
|
-
} else if (lower.includes("occupancy") || lower.includes("occupancytype")) {
|
|
3409
|
-
group.set("occupancy", f.value);
|
|
3410
|
-
} else if (lower.includes("yearbuilt")) {
|
|
3411
|
-
group.set("yearBuilt", f.value);
|
|
3412
|
-
} else if (lower.includes("squarefootage") || lower.includes("sqft") || lower.includes("area")) {
|
|
3413
|
-
group.set("squareFootage", f.value);
|
|
3414
|
-
} else if (lower.includes("protectionclass") || lower.includes("fireprotection")) {
|
|
3415
|
-
group.set("protectionClass", f.value);
|
|
3416
|
-
} else if (lower.includes("sprinkler")) {
|
|
3417
|
-
group.set("sprinklered", f.value);
|
|
3418
|
-
} else if (lower.includes("buildingvalue") || lower.includes("buildingamt") || lower.includes("buildingcoverage")) {
|
|
3419
|
-
group.set("buildingValue", f.value);
|
|
3420
|
-
} else if (lower.includes("contentsvalue") || lower.includes("contentsamt") || lower.includes("contentscoverage")) {
|
|
3421
|
-
group.set("contentsValue", f.value);
|
|
3422
|
-
} else if (lower.includes("businessincome") || lower.includes("bivalue") || lower.includes("businessincomevalue")) {
|
|
3423
|
-
group.set("businessIncomeValue", f.value);
|
|
3424
|
-
} else if (lower.includes("description") || lower.includes("buildingdescription") || lower.includes("locationdescription")) {
|
|
3425
|
-
group.set("description", f.value);
|
|
3426
|
-
} else if (lower.includes("address") || lower.includes("industryaddress") || lower.includes("locationaddress") || lower.includes("premisesaddress")) {
|
|
3427
|
-
group.set("address", f.value);
|
|
3428
|
-
} else if (lower.includes("alarm") || lower.includes("alarmtype")) {
|
|
3429
|
-
group.set("alarmType", f.value);
|
|
3430
|
-
}
|
|
3431
|
-
}
|
|
3432
|
-
if (locationGroups.size === 0) return;
|
|
3433
|
-
const locations = [];
|
|
3434
|
-
for (const [, group] of locationGroups) {
|
|
3435
|
-
const num = parseInt(group.get("number") ?? "0", 10) || locations.length + 1;
|
|
3436
|
-
const addressStr = group.get("address");
|
|
3437
|
-
locations.push({
|
|
3438
|
-
number: num,
|
|
3439
|
-
address: addressStr ? { street1: addressStr } : { street1: "See declarations" },
|
|
3440
|
-
...group.get("description") ? { description: group.get("description") } : {},
|
|
3441
|
-
...group.get("constructionType") ? { constructionType: group.get("constructionType") } : {},
|
|
3442
|
-
...group.get("occupancy") ? { occupancy: group.get("occupancy") } : {},
|
|
3443
|
-
...group.get("yearBuilt") ? { yearBuilt: parseInt(group.get("yearBuilt"), 10) || void 0 } : {},
|
|
3444
|
-
...group.get("squareFootage") ? { squareFootage: parseInt(group.get("squareFootage").replace(/[^0-9]/g, ""), 10) || void 0 } : {},
|
|
3445
|
-
...group.get("protectionClass") ? { protectionClass: group.get("protectionClass") } : {},
|
|
3446
|
-
...group.get("sprinklered") ? { sprinklered: /yes|true/i.test(group.get("sprinklered")) } : {},
|
|
3447
|
-
...group.get("buildingValue") ? { buildingValue: group.get("buildingValue") } : {},
|
|
3448
|
-
...group.get("contentsValue") ? { contentsValue: group.get("contentsValue") } : {},
|
|
3449
|
-
...group.get("businessIncomeValue") ? { businessIncomeValue: group.get("businessIncomeValue") } : {},
|
|
3450
|
-
...group.get("alarmType") ? { alarmType: group.get("alarmType") } : {}
|
|
3451
|
-
});
|
|
3452
|
-
}
|
|
3453
|
-
if (locations.length > 0) {
|
|
3454
|
-
raw.locations = locations;
|
|
3455
|
-
}
|
|
3456
|
-
}
|
|
3457
|
-
function normalizeName(name) {
|
|
3458
|
-
return name.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
3459
|
-
}
|
|
3460
|
-
var LIMIT_COVERAGE_MAP = [
|
|
3461
|
-
// GL standard
|
|
3462
|
-
[["eachoccurrence", "peroccurrence", "occurrencecombined"], "perOccurrence"],
|
|
3463
|
-
[["generalaggregate"], "generalAggregate"],
|
|
3464
|
-
[["productscompletedoperationsaggregate", "productscompletedopsaggregate", "prodcompopsagg"], "productsCompletedOpsAggregate"],
|
|
3465
|
-
[["personaladvertisinginjury", "personaladvinjury", "pai"], "personalAdvertisingInjury"],
|
|
3466
|
-
[["firedamage", "firedamagelegalliability", "damagetorentedpremises", "damagetopremisesrentedtoyou"], "fireDamage"],
|
|
3467
|
-
[["medicalexpense", "medexp", "medicalexpenseanypersonanyperson", "medicalexpenseanyone"], "medicalExpense"],
|
|
3468
|
-
// Auto
|
|
3469
|
-
[["combinedsingle", "combinedsinglelimit", "csl"], "combinedSingleLimit"],
|
|
3470
|
-
[["bodilyinjuryperperson", "biperperson"], "bodilyInjuryPerPerson"],
|
|
3471
|
-
[["bodilyinjuryperaccident", "biperaccident"], "bodilyInjuryPerAccident"],
|
|
3472
|
-
[["propertydamage", "pdperaccident"], "propertyDamage"],
|
|
3473
|
-
// Umbrella/Excess
|
|
3474
|
-
[["umbrellaoccurrence", "eachoccurrenceumbrella", "excessoccurrence", "excesseachoccurrence"], "eachOccurrenceUmbrella"],
|
|
3475
|
-
[["umbrellaaggregate", "excessaggregate"], "umbrellaAggregate"],
|
|
3476
|
-
[["umbrella retention", "selfinsuredretention", "sir", "excessretention"], "umbrellaRetention"]
|
|
3477
|
-
];
|
|
3478
|
-
function synthesizeLimits(doc) {
|
|
3479
|
-
const raw = doc;
|
|
3480
|
-
if (raw.limits && typeof raw.limits === "object" && Object.keys(raw.limits).length > 0) return;
|
|
3481
|
-
const coverages = doc.coverages;
|
|
3482
|
-
if (!coverages || coverages.length === 0) return;
|
|
3483
|
-
const limits = {};
|
|
3484
|
-
for (const cov of coverages) {
|
|
3485
|
-
if (!cov.name || !cov.limit) continue;
|
|
3486
|
-
const normalized = normalizeName(cov.name);
|
|
3487
|
-
for (const [patterns, fieldName] of LIMIT_COVERAGE_MAP) {
|
|
3488
|
-
if (patterns.some((p) => normalized.includes(p) || p.includes(normalized))) {
|
|
3489
|
-
if (fieldName.includes("Aggregate") || fieldName.includes("aggregate")) {
|
|
3490
|
-
if (!cov.limitType || cov.limitType === "aggregate") {
|
|
3491
|
-
limits[fieldName] = cov.limit;
|
|
3492
|
-
}
|
|
3493
|
-
} else {
|
|
3494
|
-
if (!limits[fieldName]) {
|
|
3495
|
-
limits[fieldName] = cov.limit;
|
|
3496
|
-
}
|
|
3497
|
-
}
|
|
3498
|
-
break;
|
|
3499
|
-
}
|
|
3500
|
-
}
|
|
3501
|
-
}
|
|
3502
|
-
const hasStatutory = coverages.some(
|
|
3503
|
-
(c) => c.limitType === "statutory" || normalizeName(c.name ?? "").includes("statutory")
|
|
3504
|
-
);
|
|
3505
|
-
if (hasStatutory) {
|
|
3506
|
-
limits.statutory = "true";
|
|
3507
|
-
}
|
|
3508
|
-
const elCoverages = coverages.filter(
|
|
3509
|
-
(c) => normalizeName(c.name ?? "").includes("employersliability")
|
|
3510
|
-
);
|
|
3511
|
-
if (elCoverages.length > 0) {
|
|
3512
|
-
const el = {};
|
|
3513
|
-
for (const c of elCoverages) {
|
|
3514
|
-
if (!c.limit) continue;
|
|
3515
|
-
const n = normalizeName(c.name ?? "");
|
|
3516
|
-
if (n.includes("accident") || n.includes("eachaccident")) el.eachAccident = c.limit;
|
|
3517
|
-
else if (n.includes("diseasepolicy") || n.includes("diseasepolicylimit")) el.diseasePolicyLimit = c.limit;
|
|
3518
|
-
else if (n.includes("diseaseemployee") || n.includes("diseaseeachemployee")) el.diseaseEachEmployee = c.limit;
|
|
3519
|
-
else if (!el.eachAccident) el.eachAccident = c.limit;
|
|
3520
|
-
}
|
|
3521
|
-
if (Object.keys(el).length > 0) {
|
|
3522
|
-
limits.employersLiability = el;
|
|
3523
|
-
}
|
|
3524
|
-
}
|
|
3525
|
-
if (Object.keys(limits).length > 0) {
|
|
3526
|
-
const result = { ...limits };
|
|
3527
|
-
if (result.statutory === "true") result.statutory = true;
|
|
3528
|
-
raw.limits = result;
|
|
3529
|
-
}
|
|
3530
|
-
}
|
|
3531
|
-
function synthesizeDeductibles(doc) {
|
|
3532
|
-
const raw = doc;
|
|
3533
|
-
if (raw.deductibles && typeof raw.deductibles === "object" && Object.keys(raw.deductibles).length > 0) return;
|
|
3534
|
-
const coverages = doc.coverages;
|
|
3535
|
-
if (!coverages || coverages.length === 0) return;
|
|
3536
|
-
const deductibleValues = coverages.filter((c) => c.deductible && c.deductible.trim() !== "" && c.deductible !== "N/A" && c.deductible !== "None").map((c) => c.deductible);
|
|
3537
|
-
if (deductibleValues.length === 0) return;
|
|
3538
|
-
const freq = /* @__PURE__ */ new Map();
|
|
3539
|
-
for (const d of deductibleValues) {
|
|
3540
|
-
freq.set(d, (freq.get(d) ?? 0) + 1);
|
|
3541
|
-
}
|
|
3542
|
-
let mostCommon = deductibleValues[0];
|
|
3543
|
-
let maxFreq = 0;
|
|
3544
|
-
for (const [val, count] of freq) {
|
|
3545
|
-
if (count > maxFreq) {
|
|
3546
|
-
mostCommon = val;
|
|
3547
|
-
maxFreq = count;
|
|
3548
|
-
}
|
|
3549
|
-
}
|
|
3550
|
-
const deductibles = {};
|
|
3551
|
-
const hasPerClaim = coverages.some(
|
|
3552
|
-
(c) => c.deductible && normalizeName(c.name ?? "").includes("perclaim")
|
|
3553
|
-
);
|
|
3554
|
-
if (hasPerClaim) {
|
|
3555
|
-
deductibles.perClaim = mostCommon;
|
|
3556
|
-
} else {
|
|
3557
|
-
deductibles.perOccurrence = mostCommon;
|
|
3558
|
-
}
|
|
3559
|
-
const sirCoverage = coverages.find(
|
|
3560
|
-
(c) => c.deductible && (normalizeName(c.name ?? "").includes("selfinsuredretention") || normalizeName(c.name ?? "").includes("sir"))
|
|
3561
|
-
);
|
|
3562
|
-
if (sirCoverage?.deductible) {
|
|
3563
|
-
deductibles.selfInsuredRetention = sirCoverage.deductible;
|
|
3564
|
-
}
|
|
3565
|
-
const aggDed = coverages.find(
|
|
3566
|
-
(c) => c.deductible && normalizeName(c.name ?? "").includes("aggregatedeductible")
|
|
3567
|
-
);
|
|
3568
|
-
if (aggDed?.deductible) {
|
|
3569
|
-
deductibles.aggregateDeductible = aggDed.deductible;
|
|
3570
|
-
}
|
|
3571
|
-
if (Object.keys(deductibles).length > 0) {
|
|
3572
|
-
raw.deductibles = deductibles;
|
|
3573
|
-
}
|
|
3574
|
-
}
|
|
3575
|
-
var PREMIUM_PATTERNS = [
|
|
3576
|
-
"premium",
|
|
3577
|
-
"premiumAmount",
|
|
3578
|
-
"premium amount",
|
|
3579
|
-
"totalPremium",
|
|
3580
|
-
"total premium",
|
|
3581
|
-
"totalPolicyPremium",
|
|
3582
|
-
"total policy premium",
|
|
3583
|
-
"annualPremium",
|
|
3584
|
-
"annual premium",
|
|
3585
|
-
"estimatedAnnualPremium",
|
|
3586
|
-
"estimated annual premium",
|
|
3587
|
-
"policyPremium",
|
|
3588
|
-
"policy premium",
|
|
3589
|
-
"basePremium",
|
|
3590
|
-
"base premium",
|
|
3591
|
-
"planCost",
|
|
3592
|
-
"plan cost",
|
|
3593
|
-
"policyCost",
|
|
3594
|
-
"policy cost",
|
|
3595
|
-
"premiumSubtotal",
|
|
3596
|
-
"premium subtotal",
|
|
3597
|
-
"subtotalPremium",
|
|
3598
|
-
"subtotal premium",
|
|
3599
|
-
"quotedPremium",
|
|
3600
|
-
"quoted premium"
|
|
3601
|
-
];
|
|
3602
|
-
var TOTAL_COST_PATTERNS = [
|
|
3603
|
-
"totalCost",
|
|
3604
|
-
"total cost",
|
|
3605
|
-
"total",
|
|
3606
|
-
"totalDue",
|
|
3607
|
-
"total due",
|
|
3608
|
-
"amountPaid",
|
|
3609
|
-
"amount paid",
|
|
3610
|
-
"totalPaid",
|
|
3611
|
-
"total paid",
|
|
3612
|
-
"totalPrice",
|
|
3613
|
-
"total price",
|
|
3614
|
-
"totalTripCost",
|
|
3615
|
-
"total trip cost",
|
|
3616
|
-
"amountCharged",
|
|
3617
|
-
"amount charged",
|
|
3618
|
-
"amountDue",
|
|
3619
|
-
"amount due",
|
|
3620
|
-
"totalAmountDue",
|
|
3621
|
-
"total amount due",
|
|
3622
|
-
"totalAmount",
|
|
3623
|
-
"total amount",
|
|
3624
|
-
"grandTotal",
|
|
3625
|
-
"grand total",
|
|
3626
|
-
"totalPayable",
|
|
3627
|
-
"total payable",
|
|
3628
|
-
"totalCharges",
|
|
3629
|
-
"total charges",
|
|
3630
|
-
"totalPolicyCost",
|
|
3631
|
-
"total policy cost"
|
|
3632
|
-
];
|
|
3633
|
-
var PREMIUM_RAW_KEYS = [
|
|
3634
|
-
"premium",
|
|
3635
|
-
"premiumAmount",
|
|
3636
|
-
"premium_amount",
|
|
3637
|
-
"totalPremium",
|
|
3638
|
-
"totalPolicyPremium",
|
|
3639
|
-
"annualPremium",
|
|
3640
|
-
"estimatedAnnualPremium",
|
|
3641
|
-
"policyPremium",
|
|
3642
|
-
"basePremium",
|
|
3643
|
-
"planCost",
|
|
3644
|
-
"policyCost",
|
|
3645
|
-
"premiumSubtotal",
|
|
3646
|
-
"subtotalPremium",
|
|
3647
|
-
"quotedPremium"
|
|
3648
|
-
];
|
|
3649
|
-
var TOTAL_COST_RAW_KEYS = [
|
|
3650
|
-
"totalCost",
|
|
3651
|
-
"total_cost",
|
|
3652
|
-
"total",
|
|
3653
|
-
"totalDue",
|
|
3654
|
-
"amountPaid",
|
|
3655
|
-
"amount_paid",
|
|
3656
|
-
"totalPaid",
|
|
3657
|
-
"total_paid",
|
|
3658
|
-
"totalPrice",
|
|
3659
|
-
"totalTripCost",
|
|
3660
|
-
"amountCharged",
|
|
3661
|
-
"amountDue",
|
|
3662
|
-
"totalAmountDue",
|
|
3663
|
-
"totalAmount",
|
|
3664
|
-
"grandTotal",
|
|
3665
|
-
"totalPayable",
|
|
3666
|
-
"totalCharges",
|
|
3667
|
-
"totalPolicyCost"
|
|
3668
|
-
];
|
|
3669
|
-
function isTaxOrFeeField(fieldName) {
|
|
3670
|
-
const normalized = normalizeFieldName(fieldName);
|
|
3671
|
-
return /tax|gst|hst|pst|qst|fee|surcharge|assessment|stamp|filing|inspection/.test(normalized);
|
|
3672
|
-
}
|
|
3673
|
-
function isTotalCostField(fieldName) {
|
|
3674
|
-
return fieldMatches(fieldName, TOTAL_COST_PATTERNS);
|
|
3675
|
-
}
|
|
3676
|
-
function taxFeeType(fieldName) {
|
|
3677
|
-
const normalized = normalizeFieldName(fieldName);
|
|
3678
|
-
if (normalized.includes("tax") || ["gst", "hst", "pst", "qst"].some((token) => normalized.includes(token))) return "tax";
|
|
3679
|
-
if (normalized.includes("surcharge")) return "surcharge";
|
|
3680
|
-
if (normalized.includes("assessment")) return "assessment";
|
|
3681
|
-
if (normalized.includes("fee") || normalized.includes("stamp") || normalized.includes("filing")) return "fee";
|
|
3682
|
-
return void 0;
|
|
3683
|
-
}
|
|
3684
|
-
function titleizeFieldName(fieldName) {
|
|
3685
|
-
const spaced = fieldName.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim();
|
|
3686
|
-
return spaced.replace(/\b\w/g, (letter) => letter.toUpperCase());
|
|
3687
|
-
}
|
|
3688
|
-
function taxFeeKey(item) {
|
|
3689
|
-
return [
|
|
3690
|
-
normalizeFieldName(item.name),
|
|
3691
|
-
normalizeFieldName(item.amount),
|
|
3692
|
-
item.type ?? ""
|
|
3693
|
-
].join("|");
|
|
3694
|
-
}
|
|
3695
|
-
function taxFeeItemFromField(field) {
|
|
3696
|
-
const type = taxFeeType(field.field);
|
|
3697
|
-
return {
|
|
3698
|
-
name: titleizeFieldName(field.field),
|
|
3699
|
-
amount: absorbNegative(field.value),
|
|
3700
|
-
...type ? { type } : {}
|
|
3701
|
-
};
|
|
3702
|
-
}
|
|
3703
|
-
function absorbNegative(value) {
|
|
3704
|
-
return value.replace(/^-\s*/, "").replace(/^\(\s*(.*?)\s*\)$/, "$1");
|
|
3705
|
-
}
|
|
3706
|
-
function promotePremium(doc) {
|
|
3707
|
-
const raw = doc;
|
|
3708
|
-
const fields = getDeclarationFields(doc);
|
|
3709
|
-
promoteRawOrDeclarationString(raw, fields, "premium", PREMIUM_RAW_KEYS, {
|
|
3710
|
-
patterns: PREMIUM_PATTERNS,
|
|
3711
|
-
reject: (field) => isTaxOrFeeField(field.field)
|
|
3712
|
-
});
|
|
3713
|
-
promoteRawOrDeclarationString(raw, fields, "totalCost", TOTAL_COST_RAW_KEYS, {
|
|
3714
|
-
patterns: TOTAL_COST_PATTERNS
|
|
3715
|
-
});
|
|
3716
|
-
if (typeof raw.premium === "string") raw.premium = absorbNegative(raw.premium);
|
|
3717
|
-
if (typeof raw.totalCost === "string") raw.totalCost = absorbNegative(raw.totalCost);
|
|
3718
|
-
}
|
|
3719
|
-
function synthesizeTaxesAndFees(doc) {
|
|
3720
|
-
const raw = doc;
|
|
3721
|
-
const fields = getDeclarationFields(doc);
|
|
3722
|
-
if (fields.length === 0) return;
|
|
3723
|
-
const existing = Array.isArray(raw.taxesAndFees) ? raw.taxesAndFees : [];
|
|
3724
|
-
const byKey = /* @__PURE__ */ new Map();
|
|
3725
|
-
for (const item of existing) {
|
|
3726
|
-
if (!item?.name || !item?.amount) continue;
|
|
3727
|
-
byKey.set(taxFeeKey(item), item);
|
|
3728
|
-
}
|
|
3729
|
-
for (const field of fields) {
|
|
3730
|
-
if (!field.value?.trim()) continue;
|
|
3731
|
-
if (!isTaxOrFeeField(field.field)) continue;
|
|
3732
|
-
if (isTotalCostField(field.field)) continue;
|
|
3733
|
-
const item = taxFeeItemFromField(field);
|
|
3734
|
-
byKey.set(taxFeeKey(item), item);
|
|
3735
|
-
}
|
|
3736
|
-
if (byKey.size > 0) {
|
|
3737
|
-
raw.taxesAndFees = [...byKey.values()];
|
|
3738
|
-
}
|
|
3739
|
-
}
|
|
3740
3280
|
function promoteExtractedFields(doc) {
|
|
3741
3281
|
promoteCarrierFields(doc);
|
|
3742
3282
|
promoteBroker(doc);
|
|
3743
|
-
promoteLossPayees(doc);
|
|
3744
|
-
promoteLocations(doc);
|
|
3745
|
-
synthesizeLimits(doc);
|
|
3746
|
-
synthesizeDeductibles(doc);
|
|
3747
|
-
synthesizeTaxesAndFees(doc);
|
|
3748
|
-
promotePremium(doc);
|
|
3749
3283
|
}
|
|
3750
3284
|
|
|
3751
3285
|
// src/extraction/alignment.ts
|
|
@@ -6468,6 +6002,12 @@ Focus on:
|
|
|
6468
6002
|
|
|
6469
6003
|
Look on the declarations page, named insured schedule, loss payee schedule, mortgagee schedule, and any endorsements that add or modify named insureds, loss payees, or mortgage holders.
|
|
6470
6004
|
|
|
6005
|
+
Critical rules:
|
|
6006
|
+
- Prefer declaration-table labels such as "Named Insured", "Named Insured and Address", "Applicant", or "Insured" over contact blocks, notice contacts, authorized officers, licensing statements, signatures, and corporate-authority wording.
|
|
6007
|
+
- Do not use an authorized officer, broker, producer, contact person, officer title, email address owner, or licensing/entity-status statement as the primary insured unless that exact person/entity is explicitly labeled as the named insured.
|
|
6008
|
+
- If a row combines the insured name with a mailing address, put the legal name in insuredName and the mailing address in insuredAddress.
|
|
6009
|
+
- Entity type must come from the insured's own legal suffix or an explicit declaration field, not from generic incorporation/licensing notices elsewhere in the policy.
|
|
6010
|
+
|
|
6471
6011
|
Return JSON only.`;
|
|
6472
6012
|
}
|
|
6473
6013
|
|
|
@@ -6501,7 +6041,9 @@ For EACH coverage, also extract:
|
|
|
6501
6041
|
- sectionRef: the declarations/schedule/endorsement section heading where it appears
|
|
6502
6042
|
- originalContent: the verbatim row or short source snippet used for this coverage
|
|
6503
6043
|
- limitType: when applicable, classify the limit as per_occurrence, per_claim, aggregate, per_person, per_accident, statutory, blanket, or scheduled
|
|
6044
|
+
- limitAmount: the limit as a plain number with no currency symbols or commas when the source states a fixed numeric currency amount
|
|
6504
6045
|
- limitValueType: classify the limit as numeric, included, not_included, as_stated, waiting_period, referential, or other
|
|
6046
|
+
- deductibleAmount: the deductible or retention as a plain number with no currency symbols or commas when the source states a fixed numeric currency amount
|
|
6505
6047
|
- deductibleValueType: classify the deductible/value term similarly when deductible is present
|
|
6506
6048
|
|
|
6507
6049
|
Critical rules:
|
|
@@ -6510,6 +6052,7 @@ Critical rules:
|
|
|
6510
6052
|
- Do not treat a generic waiting period, deductible explanation, limits clause, coinsurance clause, or definitions text as a standalone coverage unless the page contains an actual policy-specific schedule row or declaration entry.
|
|
6511
6053
|
- Values like "Included" or "Not Included" are valid only when they appear as an explicit declarations/schedule/endorsement entry for a named coverage. Do not infer them from narrative form language.
|
|
6512
6054
|
- If a waiting period or hour deductible is shown as part of a specific declarations/schedule row, it may be captured in deductible. Otherwise omit it.
|
|
6055
|
+
- Only populate limitAmount and deductibleAmount from actual policy-specific declaration, schedule, or endorsement values. Do not calculate them from examples, definitions, rating narratives, or generic form language.
|
|
6513
6056
|
- Use limitValueType or deductibleValueType to preserve non-numeric terms precisely instead of forcing them into numeric semantics.
|
|
6514
6057
|
- Preserve one row per real coverage entry. Do not merge adjacent schedule rows into malformed names.
|
|
6515
6058
|
- Keep individual/per-occurrence limits separate from aggregate limits even when they have the same coverage name, limit amount, deductible, and form number. Use limitType to distinguish them.
|
|
@@ -6729,22 +6272,28 @@ Return JSON only.`;
|
|
|
6729
6272
|
var import_zod32 = require("zod");
|
|
6730
6273
|
var PremiumBreakdownSchema = import_zod32.z.object({
|
|
6731
6274
|
premium: import_zod32.z.string().optional().describe("Total premium amount, e.g. '$5,000'"),
|
|
6275
|
+
premiumAmount: import_zod32.z.number().optional().describe("Total premium as a plain number with no currency symbols or commas"),
|
|
6732
6276
|
totalCost: import_zod32.z.string().optional().describe("Total cost including taxes and fees, e.g. '$5,250'"),
|
|
6277
|
+
totalCostAmount: import_zod32.z.number().optional().describe("Total cost as a plain number with no currency symbols or commas"),
|
|
6733
6278
|
premiumBreakdown: import_zod32.z.array(
|
|
6734
6279
|
import_zod32.z.object({
|
|
6735
6280
|
line: import_zod32.z.string().describe("Coverage line name"),
|
|
6736
|
-
amount: import_zod32.z.string().describe("Premium amount for this line")
|
|
6281
|
+
amount: import_zod32.z.string().describe("Premium amount for this line"),
|
|
6282
|
+
amountValue: import_zod32.z.number().optional().describe("Premium amount as a plain number with no currency symbols or commas")
|
|
6737
6283
|
})
|
|
6738
6284
|
).optional().describe("Per-coverage-line premium breakdown"),
|
|
6739
6285
|
taxesAndFees: import_zod32.z.array(
|
|
6740
6286
|
import_zod32.z.object({
|
|
6741
6287
|
name: import_zod32.z.string().describe("Fee or tax name"),
|
|
6742
6288
|
amount: import_zod32.z.string().describe("Dollar amount"),
|
|
6289
|
+
amountValue: import_zod32.z.number().optional().describe("Fee or tax amount as a plain number with no currency symbols or commas"),
|
|
6743
6290
|
type: import_zod32.z.enum(["tax", "fee", "surcharge", "assessment"]).optional().describe("Fee category")
|
|
6744
6291
|
})
|
|
6745
6292
|
).optional().describe("Taxes, fees, surcharges, and assessments"),
|
|
6746
6293
|
minimumPremium: import_zod32.z.string().optional().describe("Minimum premium if stated"),
|
|
6294
|
+
minimumPremiumAmount: import_zod32.z.number().optional().describe("Minimum premium as a plain number when the source states a fixed amount"),
|
|
6747
6295
|
depositPremium: import_zod32.z.string().optional().describe("Deposit premium if stated"),
|
|
6296
|
+
depositPremiumAmount: import_zod32.z.number().optional().describe("Deposit premium as a plain number when the source states a fixed amount"),
|
|
6748
6297
|
paymentPlan: import_zod32.z.string().optional().describe("Payment plan description"),
|
|
6749
6298
|
auditType: import_zod32.z.enum(["annual", "semi_annual", "quarterly", "monthly", "final", "self"]).optional().describe("Premium audit type"),
|
|
6750
6299
|
ratingBasis: import_zod32.z.string().optional().describe("Rating basis, e.g. payroll, revenue, area, units")
|
|
@@ -6754,6 +6303,7 @@ function buildPremiumBreakdownPrompt() {
|
|
|
6754
6303
|
|
|
6755
6304
|
Focus on:
|
|
6756
6305
|
- Total premium and total cost (including taxes/fees)
|
|
6306
|
+
- Plain numeric amount fields for stated money values, without currency symbols or commas
|
|
6757
6307
|
- Per-coverage-line premium breakdown if available
|
|
6758
6308
|
- Taxes, fees, surcharges, and assessments with their amounts and types
|
|
6759
6309
|
- Minimum premium and deposit premium if stated
|
|
@@ -6762,6 +6312,7 @@ Focus on:
|
|
|
6762
6312
|
- Rating basis: payroll, revenue, area, units, or other
|
|
6763
6313
|
|
|
6764
6314
|
Look on the declarations page, premium summary, and any premium/cost schedules.
|
|
6315
|
+
Prefer premium tables and schedules over definitions, exclusions, rating-basis narratives, licensing statements, or descriptions of premium trust funds. Do not use unrelated business volume, controlled written premium, deductible, limit, tax-only, fee-only, or percentage-only values as the policy premium.
|
|
6765
6316
|
|
|
6766
6317
|
Return JSON only.`;
|
|
6767
6318
|
}
|
|
@@ -8169,41 +7720,11 @@ function toReviewRoundRecord(round, review) {
|
|
|
8169
7720
|
}
|
|
8170
7721
|
|
|
8171
7722
|
// src/extraction/planning.ts
|
|
8172
|
-
function normalizePageAssignments(pageAssignments,
|
|
8173
|
-
const pageFormTypes = /* @__PURE__ */ new Map();
|
|
8174
|
-
if (formInventory) {
|
|
8175
|
-
for (const form of formInventory.forms) {
|
|
8176
|
-
if (form.pageStart != null) {
|
|
8177
|
-
const end = form.pageEnd ?? form.pageStart;
|
|
8178
|
-
for (let p = form.pageStart; p <= end; p += 1) {
|
|
8179
|
-
const types = pageFormTypes.get(p) ?? /* @__PURE__ */ new Set();
|
|
8180
|
-
types.add(form.formType);
|
|
8181
|
-
pageFormTypes.set(p, types);
|
|
8182
|
-
}
|
|
8183
|
-
}
|
|
8184
|
-
}
|
|
8185
|
-
}
|
|
7723
|
+
function normalizePageAssignments(pageAssignments, _formInventory) {
|
|
8186
7724
|
return pageAssignments.map((assignment) => {
|
|
8187
|
-
|
|
7725
|
+
const extractorNames = [...new Set(
|
|
8188
7726
|
assignment.extractorNames.filter(Boolean)
|
|
8189
7727
|
)];
|
|
8190
|
-
const hasDeclarations = extractorNames.includes("declarations");
|
|
8191
|
-
const hasConditions = extractorNames.includes("conditions");
|
|
8192
|
-
const hasExclusions = extractorNames.includes("exclusions");
|
|
8193
|
-
const hasEndorsements = extractorNames.includes("endorsements");
|
|
8194
|
-
const looksLikeScheduleValues = assignment.hasScheduleValues === true;
|
|
8195
|
-
const roleBlocksCoverageLimits = assignment.pageRole === "policy_form" || assignment.pageRole === "condition_exclusion_form" || assignment.pageRole === "endorsement_form";
|
|
8196
|
-
const inventoryTypes = pageFormTypes.get(assignment.localPageNumber);
|
|
8197
|
-
const inventoryBlocksCoverageLimits = inventoryTypes != null && !looksLikeScheduleValues && !hasDeclarations && (inventoryTypes.has("endorsement") || inventoryTypes.has("notice") || inventoryTypes.has("application"));
|
|
8198
|
-
if (extractorNames.includes("coverage_limits")) {
|
|
8199
|
-
const shouldDropCoverageLimits = inventoryBlocksCoverageLimits || !looksLikeScheduleValues && roleBlocksCoverageLimits || !hasDeclarations && !looksLikeScheduleValues && (hasConditions || hasExclusions) || !hasDeclarations && !looksLikeScheduleValues && hasEndorsements;
|
|
8200
|
-
if (shouldDropCoverageLimits) {
|
|
8201
|
-
extractorNames = extractorNames.filter((name) => name !== "coverage_limits");
|
|
8202
|
-
}
|
|
8203
|
-
}
|
|
8204
|
-
if (inventoryTypes?.has("endorsement") && !extractorNames.includes("endorsements")) {
|
|
8205
|
-
extractorNames = [...extractorNames, "endorsements"];
|
|
8206
|
-
}
|
|
8207
7728
|
return {
|
|
8208
7729
|
...assignment,
|
|
8209
7730
|
extractorNames
|
|
@@ -8542,6 +8063,18 @@ function createExtractor(config) {
|
|
|
8542
8063
|
return typeof start === "number" && typeof end === "number" && start <= endPage && end >= startPage;
|
|
8543
8064
|
});
|
|
8544
8065
|
}
|
|
8066
|
+
function formatSourceSpanText(spans) {
|
|
8067
|
+
return spans.filter((span) => span.text.trim().length > 0).map((span) => {
|
|
8068
|
+
const page = pageNumberForSpan(span);
|
|
8069
|
+
const label = [
|
|
8070
|
+
page ? `Page ${page}` : void 0,
|
|
8071
|
+
span.sectionId,
|
|
8072
|
+
span.formNumber
|
|
8073
|
+
].filter(Boolean).join(" | ");
|
|
8074
|
+
return label ? `${label}
|
|
8075
|
+
${span.text}` : span.text;
|
|
8076
|
+
}).join("\n\n---\n\n");
|
|
8077
|
+
}
|
|
8545
8078
|
function inferSectionType(title, text) {
|
|
8546
8079
|
const value = `${title} ${text.slice(0, 500)}`.toLowerCase();
|
|
8547
8080
|
if (/\bdefinition|defined terms?\b/.test(value)) return "definition";
|
|
@@ -8578,93 +8111,6 @@ function createExtractor(config) {
|
|
|
8578
8111
|
if (!line) return void 0;
|
|
8579
8112
|
return line.slice(0, 100);
|
|
8580
8113
|
}
|
|
8581
|
-
function buildDeterministicFormInventory(spans, pageCount) {
|
|
8582
|
-
if (spans.length === 0) return void 0;
|
|
8583
|
-
const formPattern = /\b([A-Z]{1,4}\s?\d{2,5}(?:\s?\d{2,4})?|[A-Z]{2,8}-\d{2,8})\b/g;
|
|
8584
|
-
const seen = /* @__PURE__ */ new Map();
|
|
8585
|
-
for (const span of spans) {
|
|
8586
|
-
const page = pageNumberForSpan(span);
|
|
8587
|
-
if (!page) continue;
|
|
8588
|
-
const title = firstHeadingLine(span.text) ?? span.sectionId;
|
|
8589
|
-
const matches = /* @__PURE__ */ new Set([
|
|
8590
|
-
...span.formNumber ? [span.formNumber] : [],
|
|
8591
|
-
...Array.from(span.text.slice(0, 1200).matchAll(formPattern), (match) => match[1].trim())
|
|
8592
|
-
]);
|
|
8593
|
-
for (const formNumber of matches) {
|
|
8594
|
-
const key = `${formNumber}:${title ?? ""}`;
|
|
8595
|
-
const existing = seen.get(key);
|
|
8596
|
-
const formType = inferFormType(title ?? "", span.text);
|
|
8597
|
-
if (existing) {
|
|
8598
|
-
existing.pageStart = Math.min(existing.pageStart ?? page, page);
|
|
8599
|
-
existing.pageEnd = Math.max(existing.pageEnd ?? page, page);
|
|
8600
|
-
continue;
|
|
8601
|
-
}
|
|
8602
|
-
seen.set(key, {
|
|
8603
|
-
formNumber,
|
|
8604
|
-
title,
|
|
8605
|
-
formType,
|
|
8606
|
-
pageStart: Math.min(page, pageCount),
|
|
8607
|
-
pageEnd: Math.min(page, pageCount)
|
|
8608
|
-
});
|
|
8609
|
-
}
|
|
8610
|
-
}
|
|
8611
|
-
const forms = [...seen.values()].sort((a, b) => (a.pageStart ?? 0) - (b.pageStart ?? 0));
|
|
8612
|
-
return forms.length > 0 ? { forms } : void 0;
|
|
8613
|
-
}
|
|
8614
|
-
function inferFormType(title, text) {
|
|
8615
|
-
const value = `${title} ${text.slice(0, 700)}`.toLowerCase();
|
|
8616
|
-
if (/\bdeclarations?|schedule\b/.test(value)) return "declarations";
|
|
8617
|
-
if (/\bendorsement|amendatory|additional insured\b/.test(value)) return "endorsement";
|
|
8618
|
-
if (/\bnotice|department of insurance|complaint|privacy\b/.test(value)) return "notice";
|
|
8619
|
-
if (/\bapplication|questionnaire\b/.test(value)) return "application";
|
|
8620
|
-
if (/\bcoverage|policy form|conditions|exclusions|definitions|causes of loss\b/.test(value)) return "coverage";
|
|
8621
|
-
return "other";
|
|
8622
|
-
}
|
|
8623
|
-
function buildDeterministicPageAssignments(spans, pageCount) {
|
|
8624
|
-
if (spans.length === 0) return [];
|
|
8625
|
-
const pageTexts = /* @__PURE__ */ new Map();
|
|
8626
|
-
for (const span of spans) {
|
|
8627
|
-
const page = pageNumberForSpan(span);
|
|
8628
|
-
if (!page) continue;
|
|
8629
|
-
pageTexts.set(page, [pageTexts.get(page), span.sectionId, span.text].filter(Boolean).join("\n"));
|
|
8630
|
-
}
|
|
8631
|
-
return Array.from({ length: pageCount }, (_, index) => {
|
|
8632
|
-
const page = index + 1;
|
|
8633
|
-
const text = pageTexts.get(page) ?? "";
|
|
8634
|
-
const lower = text.toLowerCase();
|
|
8635
|
-
const extractorNames = [];
|
|
8636
|
-
if (/\bdeclarations?|policy period|named insured|producer|schedule\b/.test(lower)) {
|
|
8637
|
-
extractorNames.push("carrier_info", "named_insured", "declarations");
|
|
8638
|
-
}
|
|
8639
|
-
if (/\blimit|deductible|premium|coinsurance|scheduled amount|blanket\b/.test(lower) && /\$|\b\d{2,}(?:,\d{3})*\b/.test(lower)) {
|
|
8640
|
-
extractorNames.push("coverage_limits");
|
|
8641
|
-
}
|
|
8642
|
-
if (/\bpremium|tax|fee|surcharge\b/.test(lower) && /\$/.test(lower)) extractorNames.push("premium_breakdown");
|
|
8643
|
-
if (/\bendorsement|additional insured|amendatory\b/.test(lower)) extractorNames.push("endorsements");
|
|
8644
|
-
if (/\bexclusion|not covered|does not apply\b/.test(lower)) extractorNames.push("exclusions");
|
|
8645
|
-
if (/\bcondition|duties in the event|loss condition|general condition\b/.test(lower)) extractorNames.push("conditions");
|
|
8646
|
-
if (/\bdefinition|defined terms?\b/.test(lower)) extractorNames.push("definitions");
|
|
8647
|
-
if (/\bcovered cause|covered peril|cause of loss|perils insured\b/.test(lower)) extractorNames.push("covered_reasons");
|
|
8648
|
-
if (textIncludesSupplementarySignal(text)) extractorNames.push("supplementary");
|
|
8649
|
-
if (extractorNames.length === 0 && text.trim().length > 180) extractorNames.push("sections");
|
|
8650
|
-
return {
|
|
8651
|
-
localPageNumber: page,
|
|
8652
|
-
extractorNames: [...new Set(extractorNames)],
|
|
8653
|
-
pageRole: inferPageRole(lower),
|
|
8654
|
-
hasScheduleValues: /\$|\b\d{2,}(?:,\d{3})*\b/.test(lower) && /\blimit|deductible|premium|schedule|class|location\b/.test(lower),
|
|
8655
|
-
confidence: text.trim().length > 0 ? 0.8 : 0,
|
|
8656
|
-
notes: "Deterministic source-span page assignment"
|
|
8657
|
-
};
|
|
8658
|
-
});
|
|
8659
|
-
}
|
|
8660
|
-
function inferPageRole(lowerText) {
|
|
8661
|
-
if (/\bdeclarations?|schedule\b/.test(lowerText)) return "declarations_schedule";
|
|
8662
|
-
if (/\bendorsement\b/.test(lowerText)) return "endorsement_form";
|
|
8663
|
-
if (/\bexclusion|condition\b/.test(lowerText)) return "condition_exclusion_form";
|
|
8664
|
-
if (/\bnotice|department of insurance|complaint\b/.test(lowerText)) return "supplementary";
|
|
8665
|
-
if (lowerText.trim()) return "policy_form";
|
|
8666
|
-
return "other";
|
|
8667
|
-
}
|
|
8668
8114
|
function shouldRunLlmReview(mode, report, sourceSpansAvailable) {
|
|
8669
8115
|
if (mode === "skip" || maxReviewRounds <= 0) return false;
|
|
8670
8116
|
if (mode === "always") return true;
|
|
@@ -8885,21 +8331,28 @@ function createExtractor(config) {
|
|
|
8885
8331
|
return promise;
|
|
8886
8332
|
}
|
|
8887
8333
|
async function getPageRangeText(startPage, endPage) {
|
|
8888
|
-
|
|
8334
|
+
if (doclingDocument) return getDoclingPageRangeText(doclingDocument, startPage, endPage);
|
|
8335
|
+
return formatSourceSpanText(spansForPageRange(sourceSpans, startPage, endPage));
|
|
8889
8336
|
}
|
|
8890
8337
|
function withFullDocumentTextContext(prompt) {
|
|
8891
|
-
if (
|
|
8892
|
-
return `${prompt}
|
|
8338
|
+
if (doclingDocument) return `${prompt}
|
|
8893
8339
|
|
|
8894
8340
|
DOCLING DOCUMENT TEXT:
|
|
8895
8341
|
${doclingDocument.fullText}`;
|
|
8342
|
+
const sourceText = formatSourceSpanText(sourceSpans);
|
|
8343
|
+
if (!sourceText) return prompt;
|
|
8344
|
+
return `${prompt}
|
|
8345
|
+
|
|
8346
|
+
SOURCE SPAN DOCUMENT TEXT:
|
|
8347
|
+
${sourceText}`;
|
|
8896
8348
|
}
|
|
8897
8349
|
function withPageRangeTextContext(prompt, startPage, endPage, pageText) {
|
|
8898
|
-
if (!
|
|
8350
|
+
if (!pageText) return prompt;
|
|
8351
|
+
const label = doclingDocument ? "DOCLING DOCUMENT" : "SOURCE SPAN DOCUMENT";
|
|
8899
8352
|
return `${prompt}
|
|
8900
8353
|
|
|
8901
|
-
|
|
8902
|
-
${pageText
|
|
8354
|
+
${label} PAGES ${startPage}-${endPage}:
|
|
8355
|
+
${pageText}`;
|
|
8903
8356
|
}
|
|
8904
8357
|
let classifyResult;
|
|
8905
8358
|
if (resumed?.classifyResult && pipelineCtx.isPhaseComplete("classify")) {
|
|
@@ -8956,17 +8409,6 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
8956
8409
|
formInventory = resumed.formInventory;
|
|
8957
8410
|
memory.set("form_inventory", formInventory);
|
|
8958
8411
|
onProgress?.("Resuming from checkpoint (form inventory complete)...");
|
|
8959
|
-
} else if (sourceSpans.length > 0) {
|
|
8960
|
-
formInventory = buildDeterministicFormInventory(sourceSpans, pageCount) ?? { forms: [] };
|
|
8961
|
-
onProgress?.(`Built deterministic form inventory for ${primaryType} ${documentType}.`);
|
|
8962
|
-
memory.set("form_inventory", formInventory);
|
|
8963
|
-
await pipelineCtx.save("form_inventory", {
|
|
8964
|
-
id,
|
|
8965
|
-
pageCount,
|
|
8966
|
-
classifyResult,
|
|
8967
|
-
formInventory,
|
|
8968
|
-
memory: Object.fromEntries(memory)
|
|
8969
|
-
});
|
|
8970
8412
|
} else {
|
|
8971
8413
|
onProgress?.(`Building form inventory for ${primaryType} ${documentType}...`);
|
|
8972
8414
|
const budget = resolveBudget("extraction_form_inventory", 2048);
|
|
@@ -9007,20 +8449,6 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
9007
8449
|
if (resumed?.pageAssignments && pipelineCtx.isPhaseComplete("page_map")) {
|
|
9008
8450
|
pageAssignments = resumed.pageAssignments;
|
|
9009
8451
|
onProgress?.("Resuming from checkpoint (page map complete)...");
|
|
9010
|
-
} else if (sourceSpans.length > 0) {
|
|
9011
|
-
onProgress?.(`Mapping document pages from source spans for ${primaryType} ${documentType}...`);
|
|
9012
|
-
pageAssignments = normalizePageAssignments(
|
|
9013
|
-
buildDeterministicPageAssignments(sourceSpans, pageCount),
|
|
9014
|
-
formInventory
|
|
9015
|
-
);
|
|
9016
|
-
await pipelineCtx.save("page_map", {
|
|
9017
|
-
id,
|
|
9018
|
-
pageCount,
|
|
9019
|
-
classifyResult,
|
|
9020
|
-
formInventory,
|
|
9021
|
-
pageAssignments,
|
|
9022
|
-
memory: Object.fromEntries(memory)
|
|
9023
|
-
});
|
|
9024
8452
|
} else {
|
|
9025
8453
|
onProgress?.(`Mapping document pages for ${primaryType} ${documentType}...`);
|
|
9026
8454
|
const chunkSize = 8;
|
|
@@ -9037,7 +8465,7 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
9037
8465
|
pageMapChunks.map(
|
|
9038
8466
|
({ startPage, endPage }) => pageMapLimit(async () => {
|
|
9039
8467
|
const pagesPdf = doclingDocument ? void 0 : await getPageRangePdf(startPage, endPage);
|
|
9040
|
-
const pagesText =
|
|
8468
|
+
const pagesText = await getPageRangeText(startPage, endPage);
|
|
9041
8469
|
const budget = resolveBudget("extraction_page_map", 2048);
|
|
9042
8470
|
const startedAt = Date.now();
|
|
9043
8471
|
const mapResponse = await safeGenerateObject(
|
|
@@ -9144,7 +8572,7 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
9144
8572
|
completedPageRangePdfCache,
|
|
9145
8573
|
getPageRangePdf,
|
|
9146
8574
|
convertPdfToImages ? getPageImages : void 0,
|
|
9147
|
-
doclingDocument ? getPageRangeText : void 0
|
|
8575
|
+
sourceSpans.length > 0 || doclingDocument ? getPageRangeText : void 0
|
|
9148
8576
|
);
|
|
9149
8577
|
})
|
|
9150
8578
|
)
|
|
@@ -9177,7 +8605,7 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
9177
8605
|
pageRangeCache: completedPageRangePdfCache,
|
|
9178
8606
|
getPageRangePdf,
|
|
9179
8607
|
getPageImages: convertPdfToImages ? getPageImages : void 0,
|
|
9180
|
-
getPageRangeText: doclingDocument ? getPageRangeText : void 0
|
|
8608
|
+
getPageRangeText: sourceSpans.length > 0 || doclingDocument ? getPageRangeText : void 0
|
|
9181
8609
|
});
|
|
9182
8610
|
trackUsage(supplementaryResult.usage, {
|
|
9183
8611
|
taskKind: "extraction_focused",
|
|
@@ -9213,7 +8641,7 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
9213
8641
|
concurrency,
|
|
9214
8642
|
getPageRangePdf,
|
|
9215
8643
|
getPageImages: convertPdfToImages ? getPageImages : void 0,
|
|
9216
|
-
getPageRangeText: doclingDocument ? getPageRangeText : void 0,
|
|
8644
|
+
getPageRangeText: sourceSpans.length > 0 || doclingDocument ? getPageRangeText : void 0,
|
|
9217
8645
|
providerOptions: activeProviderOptions,
|
|
9218
8646
|
modelCapabilities,
|
|
9219
8647
|
modelBudgetConstraints,
|
|
@@ -9309,7 +8737,7 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
9309
8737
|
completedPageRangePdfCache,
|
|
9310
8738
|
getPageRangePdf,
|
|
9311
8739
|
convertPdfToImages ? getPageImages : void 0,
|
|
9312
|
-
doclingDocument ? getPageRangeText : void 0
|
|
8740
|
+
sourceSpans.length > 0 || doclingDocument ? getPageRangeText : void 0
|
|
9313
8741
|
);
|
|
9314
8742
|
})
|
|
9315
8743
|
)
|