@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.mjs
CHANGED
|
@@ -572,6 +572,7 @@ var FormReferenceSchema = z3.object({
|
|
|
572
572
|
var TaxFeeItemSchema = z3.object({
|
|
573
573
|
name: z3.string(),
|
|
574
574
|
amount: z3.string(),
|
|
575
|
+
amountValue: z3.number().optional(),
|
|
575
576
|
type: z3.enum(["tax", "fee", "surcharge", "assessment"]).optional(),
|
|
576
577
|
description: z3.string().optional()
|
|
577
578
|
});
|
|
@@ -616,9 +617,11 @@ var CoverageValueTypeSchema = z4.enum([
|
|
|
616
617
|
var CoverageSchema = z4.object({
|
|
617
618
|
name: z4.string(),
|
|
618
619
|
limit: z4.string(),
|
|
620
|
+
limitAmount: z4.number().optional(),
|
|
619
621
|
limitType: LimitTypeSchema.optional(),
|
|
620
622
|
limitValueType: CoverageValueTypeSchema.optional(),
|
|
621
623
|
deductible: z4.string().optional(),
|
|
624
|
+
deductibleAmount: z4.number().optional(),
|
|
622
625
|
deductibleValueType: CoverageValueTypeSchema.optional(),
|
|
623
626
|
formNumber: z4.string().optional(),
|
|
624
627
|
pageNumber: z4.number().optional(),
|
|
@@ -634,9 +637,11 @@ var EnrichedCoverageSchema = z4.object({
|
|
|
634
637
|
formNumber: z4.string().optional(),
|
|
635
638
|
formEditionDate: z4.string().optional(),
|
|
636
639
|
limit: z4.string(),
|
|
640
|
+
limitAmount: z4.number().optional(),
|
|
637
641
|
limitType: LimitTypeSchema.optional(),
|
|
638
642
|
limitValueType: CoverageValueTypeSchema.optional(),
|
|
639
643
|
deductible: z4.string().optional(),
|
|
644
|
+
deductibleAmount: z4.number().optional(),
|
|
640
645
|
deductibleType: DeductibleTypeSchema.optional(),
|
|
641
646
|
deductibleValueType: CoverageValueTypeSchema.optional(),
|
|
642
647
|
sir: z4.string().optional(),
|
|
@@ -1317,7 +1322,8 @@ var UnderwritingConditionSchema = z16.object({
|
|
|
1317
1322
|
});
|
|
1318
1323
|
var PremiumLineSchema = z16.object({
|
|
1319
1324
|
line: z16.string(),
|
|
1320
|
-
amount: z16.string()
|
|
1325
|
+
amount: z16.string(),
|
|
1326
|
+
amountValue: z16.number().optional()
|
|
1321
1327
|
});
|
|
1322
1328
|
var AuxiliaryFactSchema = z16.object({
|
|
1323
1329
|
key: z16.string(),
|
|
@@ -1360,6 +1366,7 @@ var BaseDocumentFields = {
|
|
|
1360
1366
|
security: z16.string().optional(),
|
|
1361
1367
|
insuredName: z16.string(),
|
|
1362
1368
|
premium: z16.string().optional(),
|
|
1369
|
+
premiumAmount: z16.number().optional(),
|
|
1363
1370
|
summary: z16.string().optional(),
|
|
1364
1371
|
policyTypes: z16.array(z16.string()).optional(),
|
|
1365
1372
|
coverages: z16.array(CoverageSchema),
|
|
@@ -1411,8 +1418,11 @@ var BaseDocumentFields = {
|
|
|
1411
1418
|
mortgageHolders: z16.array(EndorsementPartySchema).optional(),
|
|
1412
1419
|
taxesAndFees: z16.array(TaxFeeItemSchema).optional(),
|
|
1413
1420
|
totalCost: z16.string().optional(),
|
|
1421
|
+
totalCostAmount: z16.number().optional(),
|
|
1414
1422
|
minimumPremium: z16.string().optional(),
|
|
1423
|
+
minimumPremiumAmount: z16.number().optional(),
|
|
1415
1424
|
depositPremium: z16.string().optional(),
|
|
1425
|
+
depositPremiumAmount: z16.number().optional(),
|
|
1416
1426
|
paymentPlan: PaymentPlanSchema.optional(),
|
|
1417
1427
|
auditType: AuditTypeSchema.optional(),
|
|
1418
1428
|
ratingBasis: z16.array(RatingBasisSchema).optional(),
|
|
@@ -2886,21 +2896,6 @@ function getCoveredReasons(memory) {
|
|
|
2886
2896
|
}
|
|
2887
2897
|
|
|
2888
2898
|
// src/extraction/promote.ts
|
|
2889
|
-
function getDeclarationFields(doc) {
|
|
2890
|
-
const decl = doc.declarations;
|
|
2891
|
-
return Array.isArray(decl?.fields) ? decl.fields : [];
|
|
2892
|
-
}
|
|
2893
|
-
function fieldMatches(fieldName, patterns) {
|
|
2894
|
-
const lower = normalizeFieldName(fieldName);
|
|
2895
|
-
return patterns.some((p) => lower === normalizeFieldName(p));
|
|
2896
|
-
}
|
|
2897
|
-
function normalizeFieldName(fieldName) {
|
|
2898
|
-
return fieldName.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
2899
|
-
}
|
|
2900
|
-
function findFieldValue(fields, patterns, reject) {
|
|
2901
|
-
const match = fields.find((f) => fieldMatches(f.field, patterns) && !reject?.(f));
|
|
2902
|
-
return match?.value;
|
|
2903
|
-
}
|
|
2904
2899
|
function stringValue(value) {
|
|
2905
2900
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
2906
2901
|
}
|
|
@@ -2919,14 +2914,6 @@ function promoteRawFields(raw, mappings) {
|
|
|
2919
2914
|
delete raw[from];
|
|
2920
2915
|
}
|
|
2921
2916
|
}
|
|
2922
|
-
function findRawOrDeclarationValue(raw, fields, lookup) {
|
|
2923
|
-
return (lookup.rawKey ? raw[lookup.rawKey] : void 0) || findFieldValue(fields, lookup.patterns, lookup.reject);
|
|
2924
|
-
}
|
|
2925
|
-
function promoteRawOrDeclarationString(raw, fields, targetKey, rawKeys, lookup) {
|
|
2926
|
-
if (raw[targetKey]) return;
|
|
2927
|
-
const value = findRawString(raw, rawKeys) ?? findFieldValue(fields, lookup.patterns, lookup.reject);
|
|
2928
|
-
if (value) raw[targetKey] = value;
|
|
2929
|
-
}
|
|
2930
2917
|
function promoteCarrierFields(doc) {
|
|
2931
2918
|
const raw = doc;
|
|
2932
2919
|
promoteRawFields(raw, [
|
|
@@ -2943,55 +2930,14 @@ function promoteCarrierFields(doc) {
|
|
|
2943
2930
|
};
|
|
2944
2931
|
}
|
|
2945
2932
|
}
|
|
2946
|
-
var BROKER_NAME_PATTERNS = [
|
|
2947
|
-
"brokerName",
|
|
2948
|
-
"broker",
|
|
2949
|
-
"agentName",
|
|
2950
|
-
"agent",
|
|
2951
|
-
"producerName",
|
|
2952
|
-
"producerAgency",
|
|
2953
|
-
"agencyName",
|
|
2954
|
-
"brokerAgency"
|
|
2955
|
-
];
|
|
2956
|
-
var BROKER_CONTACT_PATTERNS = [
|
|
2957
|
-
"brokerContactName",
|
|
2958
|
-
"brokerContact",
|
|
2959
|
-
"agentContactName",
|
|
2960
|
-
"producerContactName",
|
|
2961
|
-
"producerContact"
|
|
2962
|
-
];
|
|
2963
|
-
var BROKER_LICENSE_PATTERNS = [
|
|
2964
|
-
"brokerLicenseNumber",
|
|
2965
|
-
"brokerNumber",
|
|
2966
|
-
"agentLicenseNumber",
|
|
2967
|
-
"producerLicenseNumber",
|
|
2968
|
-
"producerNumber",
|
|
2969
|
-
"agentNumber"
|
|
2970
|
-
];
|
|
2971
|
-
var BROKER_PHONE_PATTERNS = ["brokerPhone", "agentPhone", "producerPhone"];
|
|
2972
|
-
var BROKER_EMAIL_PATTERNS = ["brokerEmail", "agentEmail", "producerEmail"];
|
|
2973
|
-
var BROKER_ADDRESS_PATTERNS = ["brokerAddress", "agentAddress", "producerAddress"];
|
|
2974
2933
|
function promoteBroker(doc) {
|
|
2975
2934
|
const raw = doc;
|
|
2976
|
-
const
|
|
2977
|
-
const
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
const
|
|
2982
|
-
rawKey: "brokerContactName",
|
|
2983
|
-
patterns: BROKER_CONTACT_PATTERNS
|
|
2984
|
-
});
|
|
2985
|
-
const brokerLicense = findRawOrDeclarationValue(raw, fields, {
|
|
2986
|
-
rawKey: "brokerLicenseNumber",
|
|
2987
|
-
patterns: BROKER_LICENSE_PATTERNS
|
|
2988
|
-
});
|
|
2989
|
-
const brokerPhone = findRawOrDeclarationValue(raw, fields, { patterns: BROKER_PHONE_PATTERNS });
|
|
2990
|
-
const brokerEmail = findRawOrDeclarationValue(raw, fields, { patterns: BROKER_EMAIL_PATTERNS });
|
|
2991
|
-
const brokerAddress = findRawOrDeclarationValue(raw, fields, { patterns: BROKER_ADDRESS_PATTERNS });
|
|
2992
|
-
if (brokerAgency) raw.brokerAgency = brokerAgency;
|
|
2993
|
-
if (brokerContact) raw.brokerContactName = brokerContact;
|
|
2994
|
-
if (brokerLicense) raw.brokerLicenseNumber = brokerLicense;
|
|
2935
|
+
const brokerAgency = findRawString(raw, ["brokerAgency"]);
|
|
2936
|
+
const brokerContact = findRawString(raw, ["brokerContactName"]);
|
|
2937
|
+
const brokerLicense = findRawString(raw, ["brokerLicenseNumber"]);
|
|
2938
|
+
const brokerPhone = findRawString(raw, ["brokerPhone"]);
|
|
2939
|
+
const brokerEmail = findRawString(raw, ["brokerEmail"]);
|
|
2940
|
+
const brokerAddress = findRawString(raw, ["brokerAddress"]);
|
|
2995
2941
|
if (!raw.producer && brokerAgency) {
|
|
2996
2942
|
raw.producer = {
|
|
2997
2943
|
agencyName: brokerAgency,
|
|
@@ -3003,421 +2949,9 @@ function promoteBroker(doc) {
|
|
|
3003
2949
|
};
|
|
3004
2950
|
}
|
|
3005
2951
|
}
|
|
3006
|
-
var LOSS_PAYEE_NAME_PATTERNS = [
|
|
3007
|
-
"lossPayeeName",
|
|
3008
|
-
"lossPayee",
|
|
3009
|
-
"lossPayeeHolder"
|
|
3010
|
-
];
|
|
3011
|
-
var LOSS_PAYEE_ADDRESS_PATTERNS = ["lossPayeeAddress"];
|
|
3012
|
-
var MORTGAGE_HOLDER_NAME_PATTERNS = [
|
|
3013
|
-
"mortgagee",
|
|
3014
|
-
"mortgageHolder",
|
|
3015
|
-
"mortgageHolderName",
|
|
3016
|
-
"mortgageeName",
|
|
3017
|
-
"lienholder",
|
|
3018
|
-
"lienholderName"
|
|
3019
|
-
];
|
|
3020
|
-
var MORTGAGE_HOLDER_ADDRESS_PATTERNS = [
|
|
3021
|
-
"mortgageeAddress",
|
|
3022
|
-
"mortgageHolderAddress",
|
|
3023
|
-
"lienholderAddress"
|
|
3024
|
-
];
|
|
3025
|
-
function promoteLossPayees(doc) {
|
|
3026
|
-
const raw = doc;
|
|
3027
|
-
const fields = getDeclarationFields(doc);
|
|
3028
|
-
if (!raw.lossPayees || Array.isArray(raw.lossPayees) && raw.lossPayees.length === 0) {
|
|
3029
|
-
const name = findFieldValue(fields, LOSS_PAYEE_NAME_PATTERNS);
|
|
3030
|
-
if (name) {
|
|
3031
|
-
const address = findFieldValue(fields, LOSS_PAYEE_ADDRESS_PATTERNS);
|
|
3032
|
-
raw.lossPayees = [{
|
|
3033
|
-
name,
|
|
3034
|
-
role: "loss_payee",
|
|
3035
|
-
...address ? { address: { street1: address } } : {}
|
|
3036
|
-
}];
|
|
3037
|
-
}
|
|
3038
|
-
}
|
|
3039
|
-
if (!raw.mortgageHolders || Array.isArray(raw.mortgageHolders) && raw.mortgageHolders.length === 0) {
|
|
3040
|
-
const name = findFieldValue(fields, MORTGAGE_HOLDER_NAME_PATTERNS);
|
|
3041
|
-
if (name) {
|
|
3042
|
-
const address = findFieldValue(fields, MORTGAGE_HOLDER_ADDRESS_PATTERNS);
|
|
3043
|
-
raw.mortgageHolders = [{
|
|
3044
|
-
name,
|
|
3045
|
-
role: "mortgage_holder",
|
|
3046
|
-
...address ? { address: { street1: address } } : {}
|
|
3047
|
-
}];
|
|
3048
|
-
}
|
|
3049
|
-
}
|
|
3050
|
-
}
|
|
3051
|
-
function promoteLocations(doc) {
|
|
3052
|
-
const raw = doc;
|
|
3053
|
-
if (Array.isArray(raw.locations) && raw.locations.length > 0) return;
|
|
3054
|
-
const fields = getDeclarationFields(doc);
|
|
3055
|
-
if (fields.length === 0) return;
|
|
3056
|
-
const locationGroups = /* @__PURE__ */ new Map();
|
|
3057
|
-
for (const f of fields) {
|
|
3058
|
-
const lower = f.field.toLowerCase().replace(/[\s_-]/g, "");
|
|
3059
|
-
if (lower.includes("locationnumber") || lower.includes("locnumber") || lower.includes("locno")) {
|
|
3060
|
-
const key = f.value;
|
|
3061
|
-
if (!locationGroups.has(key)) locationGroups.set(key, /* @__PURE__ */ new Map());
|
|
3062
|
-
locationGroups.get(key).set("number", f.value);
|
|
3063
|
-
continue;
|
|
3064
|
-
}
|
|
3065
|
-
if (lower.includes("buildingnumber") || lower.includes("bldgnumber") || lower.includes("bldgno")) {
|
|
3066
|
-
const lastKey2 = [...locationGroups.keys()].pop();
|
|
3067
|
-
if (lastKey2) locationGroups.get(lastKey2).set("buildingNumber", f.value);
|
|
3068
|
-
continue;
|
|
3069
|
-
}
|
|
3070
|
-
const section = (f.section ?? "").toLowerCase();
|
|
3071
|
-
const isLocationField = section.includes("location") || section.includes("building") || section.includes("premises") || section.includes("schedule of locations");
|
|
3072
|
-
if (!isLocationField) continue;
|
|
3073
|
-
if (locationGroups.size === 0) {
|
|
3074
|
-
locationGroups.set("1", /* @__PURE__ */ new Map([["number", "1"]]));
|
|
3075
|
-
}
|
|
3076
|
-
const lastKey = [...locationGroups.keys()].pop();
|
|
3077
|
-
const group = locationGroups.get(lastKey);
|
|
3078
|
-
if (lower.includes("construction") || lower.includes("constructiontype")) {
|
|
3079
|
-
group.set("constructionType", f.value);
|
|
3080
|
-
} else if (lower.includes("occupancy") || lower.includes("occupancytype")) {
|
|
3081
|
-
group.set("occupancy", f.value);
|
|
3082
|
-
} else if (lower.includes("yearbuilt")) {
|
|
3083
|
-
group.set("yearBuilt", f.value);
|
|
3084
|
-
} else if (lower.includes("squarefootage") || lower.includes("sqft") || lower.includes("area")) {
|
|
3085
|
-
group.set("squareFootage", f.value);
|
|
3086
|
-
} else if (lower.includes("protectionclass") || lower.includes("fireprotection")) {
|
|
3087
|
-
group.set("protectionClass", f.value);
|
|
3088
|
-
} else if (lower.includes("sprinkler")) {
|
|
3089
|
-
group.set("sprinklered", f.value);
|
|
3090
|
-
} else if (lower.includes("buildingvalue") || lower.includes("buildingamt") || lower.includes("buildingcoverage")) {
|
|
3091
|
-
group.set("buildingValue", f.value);
|
|
3092
|
-
} else if (lower.includes("contentsvalue") || lower.includes("contentsamt") || lower.includes("contentscoverage")) {
|
|
3093
|
-
group.set("contentsValue", f.value);
|
|
3094
|
-
} else if (lower.includes("businessincome") || lower.includes("bivalue") || lower.includes("businessincomevalue")) {
|
|
3095
|
-
group.set("businessIncomeValue", f.value);
|
|
3096
|
-
} else if (lower.includes("description") || lower.includes("buildingdescription") || lower.includes("locationdescription")) {
|
|
3097
|
-
group.set("description", f.value);
|
|
3098
|
-
} else if (lower.includes("address") || lower.includes("industryaddress") || lower.includes("locationaddress") || lower.includes("premisesaddress")) {
|
|
3099
|
-
group.set("address", f.value);
|
|
3100
|
-
} else if (lower.includes("alarm") || lower.includes("alarmtype")) {
|
|
3101
|
-
group.set("alarmType", f.value);
|
|
3102
|
-
}
|
|
3103
|
-
}
|
|
3104
|
-
if (locationGroups.size === 0) return;
|
|
3105
|
-
const locations = [];
|
|
3106
|
-
for (const [, group] of locationGroups) {
|
|
3107
|
-
const num = parseInt(group.get("number") ?? "0", 10) || locations.length + 1;
|
|
3108
|
-
const addressStr = group.get("address");
|
|
3109
|
-
locations.push({
|
|
3110
|
-
number: num,
|
|
3111
|
-
address: addressStr ? { street1: addressStr } : { street1: "See declarations" },
|
|
3112
|
-
...group.get("description") ? { description: group.get("description") } : {},
|
|
3113
|
-
...group.get("constructionType") ? { constructionType: group.get("constructionType") } : {},
|
|
3114
|
-
...group.get("occupancy") ? { occupancy: group.get("occupancy") } : {},
|
|
3115
|
-
...group.get("yearBuilt") ? { yearBuilt: parseInt(group.get("yearBuilt"), 10) || void 0 } : {},
|
|
3116
|
-
...group.get("squareFootage") ? { squareFootage: parseInt(group.get("squareFootage").replace(/[^0-9]/g, ""), 10) || void 0 } : {},
|
|
3117
|
-
...group.get("protectionClass") ? { protectionClass: group.get("protectionClass") } : {},
|
|
3118
|
-
...group.get("sprinklered") ? { sprinklered: /yes|true/i.test(group.get("sprinklered")) } : {},
|
|
3119
|
-
...group.get("buildingValue") ? { buildingValue: group.get("buildingValue") } : {},
|
|
3120
|
-
...group.get("contentsValue") ? { contentsValue: group.get("contentsValue") } : {},
|
|
3121
|
-
...group.get("businessIncomeValue") ? { businessIncomeValue: group.get("businessIncomeValue") } : {},
|
|
3122
|
-
...group.get("alarmType") ? { alarmType: group.get("alarmType") } : {}
|
|
3123
|
-
});
|
|
3124
|
-
}
|
|
3125
|
-
if (locations.length > 0) {
|
|
3126
|
-
raw.locations = locations;
|
|
3127
|
-
}
|
|
3128
|
-
}
|
|
3129
|
-
function normalizeName(name) {
|
|
3130
|
-
return name.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
3131
|
-
}
|
|
3132
|
-
var LIMIT_COVERAGE_MAP = [
|
|
3133
|
-
// GL standard
|
|
3134
|
-
[["eachoccurrence", "peroccurrence", "occurrencecombined"], "perOccurrence"],
|
|
3135
|
-
[["generalaggregate"], "generalAggregate"],
|
|
3136
|
-
[["productscompletedoperationsaggregate", "productscompletedopsaggregate", "prodcompopsagg"], "productsCompletedOpsAggregate"],
|
|
3137
|
-
[["personaladvertisinginjury", "personaladvinjury", "pai"], "personalAdvertisingInjury"],
|
|
3138
|
-
[["firedamage", "firedamagelegalliability", "damagetorentedpremises", "damagetopremisesrentedtoyou"], "fireDamage"],
|
|
3139
|
-
[["medicalexpense", "medexp", "medicalexpenseanypersonanyperson", "medicalexpenseanyone"], "medicalExpense"],
|
|
3140
|
-
// Auto
|
|
3141
|
-
[["combinedsingle", "combinedsinglelimit", "csl"], "combinedSingleLimit"],
|
|
3142
|
-
[["bodilyinjuryperperson", "biperperson"], "bodilyInjuryPerPerson"],
|
|
3143
|
-
[["bodilyinjuryperaccident", "biperaccident"], "bodilyInjuryPerAccident"],
|
|
3144
|
-
[["propertydamage", "pdperaccident"], "propertyDamage"],
|
|
3145
|
-
// Umbrella/Excess
|
|
3146
|
-
[["umbrellaoccurrence", "eachoccurrenceumbrella", "excessoccurrence", "excesseachoccurrence"], "eachOccurrenceUmbrella"],
|
|
3147
|
-
[["umbrellaaggregate", "excessaggregate"], "umbrellaAggregate"],
|
|
3148
|
-
[["umbrella retention", "selfinsuredretention", "sir", "excessretention"], "umbrellaRetention"]
|
|
3149
|
-
];
|
|
3150
|
-
function synthesizeLimits(doc) {
|
|
3151
|
-
const raw = doc;
|
|
3152
|
-
if (raw.limits && typeof raw.limits === "object" && Object.keys(raw.limits).length > 0) return;
|
|
3153
|
-
const coverages = doc.coverages;
|
|
3154
|
-
if (!coverages || coverages.length === 0) return;
|
|
3155
|
-
const limits = {};
|
|
3156
|
-
for (const cov of coverages) {
|
|
3157
|
-
if (!cov.name || !cov.limit) continue;
|
|
3158
|
-
const normalized = normalizeName(cov.name);
|
|
3159
|
-
for (const [patterns, fieldName] of LIMIT_COVERAGE_MAP) {
|
|
3160
|
-
if (patterns.some((p) => normalized.includes(p) || p.includes(normalized))) {
|
|
3161
|
-
if (fieldName.includes("Aggregate") || fieldName.includes("aggregate")) {
|
|
3162
|
-
if (!cov.limitType || cov.limitType === "aggregate") {
|
|
3163
|
-
limits[fieldName] = cov.limit;
|
|
3164
|
-
}
|
|
3165
|
-
} else {
|
|
3166
|
-
if (!limits[fieldName]) {
|
|
3167
|
-
limits[fieldName] = cov.limit;
|
|
3168
|
-
}
|
|
3169
|
-
}
|
|
3170
|
-
break;
|
|
3171
|
-
}
|
|
3172
|
-
}
|
|
3173
|
-
}
|
|
3174
|
-
const hasStatutory = coverages.some(
|
|
3175
|
-
(c) => c.limitType === "statutory" || normalizeName(c.name ?? "").includes("statutory")
|
|
3176
|
-
);
|
|
3177
|
-
if (hasStatutory) {
|
|
3178
|
-
limits.statutory = "true";
|
|
3179
|
-
}
|
|
3180
|
-
const elCoverages = coverages.filter(
|
|
3181
|
-
(c) => normalizeName(c.name ?? "").includes("employersliability")
|
|
3182
|
-
);
|
|
3183
|
-
if (elCoverages.length > 0) {
|
|
3184
|
-
const el = {};
|
|
3185
|
-
for (const c of elCoverages) {
|
|
3186
|
-
if (!c.limit) continue;
|
|
3187
|
-
const n = normalizeName(c.name ?? "");
|
|
3188
|
-
if (n.includes("accident") || n.includes("eachaccident")) el.eachAccident = c.limit;
|
|
3189
|
-
else if (n.includes("diseasepolicy") || n.includes("diseasepolicylimit")) el.diseasePolicyLimit = c.limit;
|
|
3190
|
-
else if (n.includes("diseaseemployee") || n.includes("diseaseeachemployee")) el.diseaseEachEmployee = c.limit;
|
|
3191
|
-
else if (!el.eachAccident) el.eachAccident = c.limit;
|
|
3192
|
-
}
|
|
3193
|
-
if (Object.keys(el).length > 0) {
|
|
3194
|
-
limits.employersLiability = el;
|
|
3195
|
-
}
|
|
3196
|
-
}
|
|
3197
|
-
if (Object.keys(limits).length > 0) {
|
|
3198
|
-
const result = { ...limits };
|
|
3199
|
-
if (result.statutory === "true") result.statutory = true;
|
|
3200
|
-
raw.limits = result;
|
|
3201
|
-
}
|
|
3202
|
-
}
|
|
3203
|
-
function synthesizeDeductibles(doc) {
|
|
3204
|
-
const raw = doc;
|
|
3205
|
-
if (raw.deductibles && typeof raw.deductibles === "object" && Object.keys(raw.deductibles).length > 0) return;
|
|
3206
|
-
const coverages = doc.coverages;
|
|
3207
|
-
if (!coverages || coverages.length === 0) return;
|
|
3208
|
-
const deductibleValues = coverages.filter((c) => c.deductible && c.deductible.trim() !== "" && c.deductible !== "N/A" && c.deductible !== "None").map((c) => c.deductible);
|
|
3209
|
-
if (deductibleValues.length === 0) return;
|
|
3210
|
-
const freq = /* @__PURE__ */ new Map();
|
|
3211
|
-
for (const d of deductibleValues) {
|
|
3212
|
-
freq.set(d, (freq.get(d) ?? 0) + 1);
|
|
3213
|
-
}
|
|
3214
|
-
let mostCommon = deductibleValues[0];
|
|
3215
|
-
let maxFreq = 0;
|
|
3216
|
-
for (const [val, count] of freq) {
|
|
3217
|
-
if (count > maxFreq) {
|
|
3218
|
-
mostCommon = val;
|
|
3219
|
-
maxFreq = count;
|
|
3220
|
-
}
|
|
3221
|
-
}
|
|
3222
|
-
const deductibles = {};
|
|
3223
|
-
const hasPerClaim = coverages.some(
|
|
3224
|
-
(c) => c.deductible && normalizeName(c.name ?? "").includes("perclaim")
|
|
3225
|
-
);
|
|
3226
|
-
if (hasPerClaim) {
|
|
3227
|
-
deductibles.perClaim = mostCommon;
|
|
3228
|
-
} else {
|
|
3229
|
-
deductibles.perOccurrence = mostCommon;
|
|
3230
|
-
}
|
|
3231
|
-
const sirCoverage = coverages.find(
|
|
3232
|
-
(c) => c.deductible && (normalizeName(c.name ?? "").includes("selfinsuredretention") || normalizeName(c.name ?? "").includes("sir"))
|
|
3233
|
-
);
|
|
3234
|
-
if (sirCoverage?.deductible) {
|
|
3235
|
-
deductibles.selfInsuredRetention = sirCoverage.deductible;
|
|
3236
|
-
}
|
|
3237
|
-
const aggDed = coverages.find(
|
|
3238
|
-
(c) => c.deductible && normalizeName(c.name ?? "").includes("aggregatedeductible")
|
|
3239
|
-
);
|
|
3240
|
-
if (aggDed?.deductible) {
|
|
3241
|
-
deductibles.aggregateDeductible = aggDed.deductible;
|
|
3242
|
-
}
|
|
3243
|
-
if (Object.keys(deductibles).length > 0) {
|
|
3244
|
-
raw.deductibles = deductibles;
|
|
3245
|
-
}
|
|
3246
|
-
}
|
|
3247
|
-
var PREMIUM_PATTERNS = [
|
|
3248
|
-
"premium",
|
|
3249
|
-
"premiumAmount",
|
|
3250
|
-
"premium amount",
|
|
3251
|
-
"totalPremium",
|
|
3252
|
-
"total premium",
|
|
3253
|
-
"totalPolicyPremium",
|
|
3254
|
-
"total policy premium",
|
|
3255
|
-
"annualPremium",
|
|
3256
|
-
"annual premium",
|
|
3257
|
-
"estimatedAnnualPremium",
|
|
3258
|
-
"estimated annual premium",
|
|
3259
|
-
"policyPremium",
|
|
3260
|
-
"policy premium",
|
|
3261
|
-
"basePremium",
|
|
3262
|
-
"base premium",
|
|
3263
|
-
"planCost",
|
|
3264
|
-
"plan cost",
|
|
3265
|
-
"policyCost",
|
|
3266
|
-
"policy cost",
|
|
3267
|
-
"premiumSubtotal",
|
|
3268
|
-
"premium subtotal",
|
|
3269
|
-
"subtotalPremium",
|
|
3270
|
-
"subtotal premium",
|
|
3271
|
-
"quotedPremium",
|
|
3272
|
-
"quoted premium"
|
|
3273
|
-
];
|
|
3274
|
-
var TOTAL_COST_PATTERNS = [
|
|
3275
|
-
"totalCost",
|
|
3276
|
-
"total cost",
|
|
3277
|
-
"total",
|
|
3278
|
-
"totalDue",
|
|
3279
|
-
"total due",
|
|
3280
|
-
"amountPaid",
|
|
3281
|
-
"amount paid",
|
|
3282
|
-
"totalPaid",
|
|
3283
|
-
"total paid",
|
|
3284
|
-
"totalPrice",
|
|
3285
|
-
"total price",
|
|
3286
|
-
"totalTripCost",
|
|
3287
|
-
"total trip cost",
|
|
3288
|
-
"amountCharged",
|
|
3289
|
-
"amount charged",
|
|
3290
|
-
"amountDue",
|
|
3291
|
-
"amount due",
|
|
3292
|
-
"totalAmountDue",
|
|
3293
|
-
"total amount due",
|
|
3294
|
-
"totalAmount",
|
|
3295
|
-
"total amount",
|
|
3296
|
-
"grandTotal",
|
|
3297
|
-
"grand total",
|
|
3298
|
-
"totalPayable",
|
|
3299
|
-
"total payable",
|
|
3300
|
-
"totalCharges",
|
|
3301
|
-
"total charges",
|
|
3302
|
-
"totalPolicyCost",
|
|
3303
|
-
"total policy cost"
|
|
3304
|
-
];
|
|
3305
|
-
var PREMIUM_RAW_KEYS = [
|
|
3306
|
-
"premium",
|
|
3307
|
-
"premiumAmount",
|
|
3308
|
-
"premium_amount",
|
|
3309
|
-
"totalPremium",
|
|
3310
|
-
"totalPolicyPremium",
|
|
3311
|
-
"annualPremium",
|
|
3312
|
-
"estimatedAnnualPremium",
|
|
3313
|
-
"policyPremium",
|
|
3314
|
-
"basePremium",
|
|
3315
|
-
"planCost",
|
|
3316
|
-
"policyCost",
|
|
3317
|
-
"premiumSubtotal",
|
|
3318
|
-
"subtotalPremium",
|
|
3319
|
-
"quotedPremium"
|
|
3320
|
-
];
|
|
3321
|
-
var TOTAL_COST_RAW_KEYS = [
|
|
3322
|
-
"totalCost",
|
|
3323
|
-
"total_cost",
|
|
3324
|
-
"total",
|
|
3325
|
-
"totalDue",
|
|
3326
|
-
"amountPaid",
|
|
3327
|
-
"amount_paid",
|
|
3328
|
-
"totalPaid",
|
|
3329
|
-
"total_paid",
|
|
3330
|
-
"totalPrice",
|
|
3331
|
-
"totalTripCost",
|
|
3332
|
-
"amountCharged",
|
|
3333
|
-
"amountDue",
|
|
3334
|
-
"totalAmountDue",
|
|
3335
|
-
"totalAmount",
|
|
3336
|
-
"grandTotal",
|
|
3337
|
-
"totalPayable",
|
|
3338
|
-
"totalCharges",
|
|
3339
|
-
"totalPolicyCost"
|
|
3340
|
-
];
|
|
3341
|
-
function isTaxOrFeeField(fieldName) {
|
|
3342
|
-
const normalized = normalizeFieldName(fieldName);
|
|
3343
|
-
return /tax|gst|hst|pst|qst|fee|surcharge|assessment|stamp|filing|inspection/.test(normalized);
|
|
3344
|
-
}
|
|
3345
|
-
function isTotalCostField(fieldName) {
|
|
3346
|
-
return fieldMatches(fieldName, TOTAL_COST_PATTERNS);
|
|
3347
|
-
}
|
|
3348
|
-
function taxFeeType(fieldName) {
|
|
3349
|
-
const normalized = normalizeFieldName(fieldName);
|
|
3350
|
-
if (normalized.includes("tax") || ["gst", "hst", "pst", "qst"].some((token) => normalized.includes(token))) return "tax";
|
|
3351
|
-
if (normalized.includes("surcharge")) return "surcharge";
|
|
3352
|
-
if (normalized.includes("assessment")) return "assessment";
|
|
3353
|
-
if (normalized.includes("fee") || normalized.includes("stamp") || normalized.includes("filing")) return "fee";
|
|
3354
|
-
return void 0;
|
|
3355
|
-
}
|
|
3356
|
-
function titleizeFieldName(fieldName) {
|
|
3357
|
-
const spaced = fieldName.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim();
|
|
3358
|
-
return spaced.replace(/\b\w/g, (letter) => letter.toUpperCase());
|
|
3359
|
-
}
|
|
3360
|
-
function taxFeeKey(item) {
|
|
3361
|
-
return [
|
|
3362
|
-
normalizeFieldName(item.name),
|
|
3363
|
-
normalizeFieldName(item.amount),
|
|
3364
|
-
item.type ?? ""
|
|
3365
|
-
].join("|");
|
|
3366
|
-
}
|
|
3367
|
-
function taxFeeItemFromField(field) {
|
|
3368
|
-
const type = taxFeeType(field.field);
|
|
3369
|
-
return {
|
|
3370
|
-
name: titleizeFieldName(field.field),
|
|
3371
|
-
amount: absorbNegative(field.value),
|
|
3372
|
-
...type ? { type } : {}
|
|
3373
|
-
};
|
|
3374
|
-
}
|
|
3375
|
-
function absorbNegative(value) {
|
|
3376
|
-
return value.replace(/^-\s*/, "").replace(/^\(\s*(.*?)\s*\)$/, "$1");
|
|
3377
|
-
}
|
|
3378
|
-
function promotePremium(doc) {
|
|
3379
|
-
const raw = doc;
|
|
3380
|
-
const fields = getDeclarationFields(doc);
|
|
3381
|
-
promoteRawOrDeclarationString(raw, fields, "premium", PREMIUM_RAW_KEYS, {
|
|
3382
|
-
patterns: PREMIUM_PATTERNS,
|
|
3383
|
-
reject: (field) => isTaxOrFeeField(field.field)
|
|
3384
|
-
});
|
|
3385
|
-
promoteRawOrDeclarationString(raw, fields, "totalCost", TOTAL_COST_RAW_KEYS, {
|
|
3386
|
-
patterns: TOTAL_COST_PATTERNS
|
|
3387
|
-
});
|
|
3388
|
-
if (typeof raw.premium === "string") raw.premium = absorbNegative(raw.premium);
|
|
3389
|
-
if (typeof raw.totalCost === "string") raw.totalCost = absorbNegative(raw.totalCost);
|
|
3390
|
-
}
|
|
3391
|
-
function synthesizeTaxesAndFees(doc) {
|
|
3392
|
-
const raw = doc;
|
|
3393
|
-
const fields = getDeclarationFields(doc);
|
|
3394
|
-
if (fields.length === 0) return;
|
|
3395
|
-
const existing = Array.isArray(raw.taxesAndFees) ? raw.taxesAndFees : [];
|
|
3396
|
-
const byKey = /* @__PURE__ */ new Map();
|
|
3397
|
-
for (const item of existing) {
|
|
3398
|
-
if (!item?.name || !item?.amount) continue;
|
|
3399
|
-
byKey.set(taxFeeKey(item), item);
|
|
3400
|
-
}
|
|
3401
|
-
for (const field of fields) {
|
|
3402
|
-
if (!field.value?.trim()) continue;
|
|
3403
|
-
if (!isTaxOrFeeField(field.field)) continue;
|
|
3404
|
-
if (isTotalCostField(field.field)) continue;
|
|
3405
|
-
const item = taxFeeItemFromField(field);
|
|
3406
|
-
byKey.set(taxFeeKey(item), item);
|
|
3407
|
-
}
|
|
3408
|
-
if (byKey.size > 0) {
|
|
3409
|
-
raw.taxesAndFees = [...byKey.values()];
|
|
3410
|
-
}
|
|
3411
|
-
}
|
|
3412
2952
|
function promoteExtractedFields(doc) {
|
|
3413
2953
|
promoteCarrierFields(doc);
|
|
3414
2954
|
promoteBroker(doc);
|
|
3415
|
-
promoteLossPayees(doc);
|
|
3416
|
-
promoteLocations(doc);
|
|
3417
|
-
synthesizeLimits(doc);
|
|
3418
|
-
synthesizeDeductibles(doc);
|
|
3419
|
-
synthesizeTaxesAndFees(doc);
|
|
3420
|
-
promotePremium(doc);
|
|
3421
2955
|
}
|
|
3422
2956
|
|
|
3423
2957
|
// src/extraction/alignment.ts
|
|
@@ -6140,6 +5674,12 @@ Focus on:
|
|
|
6140
5674
|
|
|
6141
5675
|
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.
|
|
6142
5676
|
|
|
5677
|
+
Critical rules:
|
|
5678
|
+
- 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.
|
|
5679
|
+
- 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.
|
|
5680
|
+
- If a row combines the insured name with a mailing address, put the legal name in insuredName and the mailing address in insuredAddress.
|
|
5681
|
+
- 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.
|
|
5682
|
+
|
|
6143
5683
|
Return JSON only.`;
|
|
6144
5684
|
}
|
|
6145
5685
|
|
|
@@ -6173,7 +5713,9 @@ For EACH coverage, also extract:
|
|
|
6173
5713
|
- sectionRef: the declarations/schedule/endorsement section heading where it appears
|
|
6174
5714
|
- originalContent: the verbatim row or short source snippet used for this coverage
|
|
6175
5715
|
- limitType: when applicable, classify the limit as per_occurrence, per_claim, aggregate, per_person, per_accident, statutory, blanket, or scheduled
|
|
5716
|
+
- limitAmount: the limit as a plain number with no currency symbols or commas when the source states a fixed numeric currency amount
|
|
6176
5717
|
- limitValueType: classify the limit as numeric, included, not_included, as_stated, waiting_period, referential, or other
|
|
5718
|
+
- deductibleAmount: the deductible or retention as a plain number with no currency symbols or commas when the source states a fixed numeric currency amount
|
|
6177
5719
|
- deductibleValueType: classify the deductible/value term similarly when deductible is present
|
|
6178
5720
|
|
|
6179
5721
|
Critical rules:
|
|
@@ -6182,6 +5724,7 @@ Critical rules:
|
|
|
6182
5724
|
- 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.
|
|
6183
5725
|
- 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.
|
|
6184
5726
|
- 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.
|
|
5727
|
+
- 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.
|
|
6185
5728
|
- Use limitValueType or deductibleValueType to preserve non-numeric terms precisely instead of forcing them into numeric semantics.
|
|
6186
5729
|
- Preserve one row per real coverage entry. Do not merge adjacent schedule rows into malformed names.
|
|
6187
5730
|
- 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.
|
|
@@ -6401,22 +5944,28 @@ Return JSON only.`;
|
|
|
6401
5944
|
import { z as z32 } from "zod";
|
|
6402
5945
|
var PremiumBreakdownSchema = z32.object({
|
|
6403
5946
|
premium: z32.string().optional().describe("Total premium amount, e.g. '$5,000'"),
|
|
5947
|
+
premiumAmount: z32.number().optional().describe("Total premium as a plain number with no currency symbols or commas"),
|
|
6404
5948
|
totalCost: z32.string().optional().describe("Total cost including taxes and fees, e.g. '$5,250'"),
|
|
5949
|
+
totalCostAmount: z32.number().optional().describe("Total cost as a plain number with no currency symbols or commas"),
|
|
6405
5950
|
premiumBreakdown: z32.array(
|
|
6406
5951
|
z32.object({
|
|
6407
5952
|
line: z32.string().describe("Coverage line name"),
|
|
6408
|
-
amount: z32.string().describe("Premium amount for this line")
|
|
5953
|
+
amount: z32.string().describe("Premium amount for this line"),
|
|
5954
|
+
amountValue: z32.number().optional().describe("Premium amount as a plain number with no currency symbols or commas")
|
|
6409
5955
|
})
|
|
6410
5956
|
).optional().describe("Per-coverage-line premium breakdown"),
|
|
6411
5957
|
taxesAndFees: z32.array(
|
|
6412
5958
|
z32.object({
|
|
6413
5959
|
name: z32.string().describe("Fee or tax name"),
|
|
6414
5960
|
amount: z32.string().describe("Dollar amount"),
|
|
5961
|
+
amountValue: z32.number().optional().describe("Fee or tax amount as a plain number with no currency symbols or commas"),
|
|
6415
5962
|
type: z32.enum(["tax", "fee", "surcharge", "assessment"]).optional().describe("Fee category")
|
|
6416
5963
|
})
|
|
6417
5964
|
).optional().describe("Taxes, fees, surcharges, and assessments"),
|
|
6418
5965
|
minimumPremium: z32.string().optional().describe("Minimum premium if stated"),
|
|
5966
|
+
minimumPremiumAmount: z32.number().optional().describe("Minimum premium as a plain number when the source states a fixed amount"),
|
|
6419
5967
|
depositPremium: z32.string().optional().describe("Deposit premium if stated"),
|
|
5968
|
+
depositPremiumAmount: z32.number().optional().describe("Deposit premium as a plain number when the source states a fixed amount"),
|
|
6420
5969
|
paymentPlan: z32.string().optional().describe("Payment plan description"),
|
|
6421
5970
|
auditType: z32.enum(["annual", "semi_annual", "quarterly", "monthly", "final", "self"]).optional().describe("Premium audit type"),
|
|
6422
5971
|
ratingBasis: z32.string().optional().describe("Rating basis, e.g. payroll, revenue, area, units")
|
|
@@ -6426,6 +5975,7 @@ function buildPremiumBreakdownPrompt() {
|
|
|
6426
5975
|
|
|
6427
5976
|
Focus on:
|
|
6428
5977
|
- Total premium and total cost (including taxes/fees)
|
|
5978
|
+
- Plain numeric amount fields for stated money values, without currency symbols or commas
|
|
6429
5979
|
- Per-coverage-line premium breakdown if available
|
|
6430
5980
|
- Taxes, fees, surcharges, and assessments with their amounts and types
|
|
6431
5981
|
- Minimum premium and deposit premium if stated
|
|
@@ -6434,6 +5984,7 @@ Focus on:
|
|
|
6434
5984
|
- Rating basis: payroll, revenue, area, units, or other
|
|
6435
5985
|
|
|
6436
5986
|
Look on the declarations page, premium summary, and any premium/cost schedules.
|
|
5987
|
+
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.
|
|
6437
5988
|
|
|
6438
5989
|
Return JSON only.`;
|
|
6439
5990
|
}
|
|
@@ -7841,41 +7392,11 @@ function toReviewRoundRecord(round, review) {
|
|
|
7841
7392
|
}
|
|
7842
7393
|
|
|
7843
7394
|
// src/extraction/planning.ts
|
|
7844
|
-
function normalizePageAssignments(pageAssignments,
|
|
7845
|
-
const pageFormTypes = /* @__PURE__ */ new Map();
|
|
7846
|
-
if (formInventory) {
|
|
7847
|
-
for (const form of formInventory.forms) {
|
|
7848
|
-
if (form.pageStart != null) {
|
|
7849
|
-
const end = form.pageEnd ?? form.pageStart;
|
|
7850
|
-
for (let p = form.pageStart; p <= end; p += 1) {
|
|
7851
|
-
const types = pageFormTypes.get(p) ?? /* @__PURE__ */ new Set();
|
|
7852
|
-
types.add(form.formType);
|
|
7853
|
-
pageFormTypes.set(p, types);
|
|
7854
|
-
}
|
|
7855
|
-
}
|
|
7856
|
-
}
|
|
7857
|
-
}
|
|
7395
|
+
function normalizePageAssignments(pageAssignments, _formInventory) {
|
|
7858
7396
|
return pageAssignments.map((assignment) => {
|
|
7859
|
-
|
|
7397
|
+
const extractorNames = [...new Set(
|
|
7860
7398
|
assignment.extractorNames.filter(Boolean)
|
|
7861
7399
|
)];
|
|
7862
|
-
const hasDeclarations = extractorNames.includes("declarations");
|
|
7863
|
-
const hasConditions = extractorNames.includes("conditions");
|
|
7864
|
-
const hasExclusions = extractorNames.includes("exclusions");
|
|
7865
|
-
const hasEndorsements = extractorNames.includes("endorsements");
|
|
7866
|
-
const looksLikeScheduleValues = assignment.hasScheduleValues === true;
|
|
7867
|
-
const roleBlocksCoverageLimits = assignment.pageRole === "policy_form" || assignment.pageRole === "condition_exclusion_form" || assignment.pageRole === "endorsement_form";
|
|
7868
|
-
const inventoryTypes = pageFormTypes.get(assignment.localPageNumber);
|
|
7869
|
-
const inventoryBlocksCoverageLimits = inventoryTypes != null && !looksLikeScheduleValues && !hasDeclarations && (inventoryTypes.has("endorsement") || inventoryTypes.has("notice") || inventoryTypes.has("application"));
|
|
7870
|
-
if (extractorNames.includes("coverage_limits")) {
|
|
7871
|
-
const shouldDropCoverageLimits = inventoryBlocksCoverageLimits || !looksLikeScheduleValues && roleBlocksCoverageLimits || !hasDeclarations && !looksLikeScheduleValues && (hasConditions || hasExclusions) || !hasDeclarations && !looksLikeScheduleValues && hasEndorsements;
|
|
7872
|
-
if (shouldDropCoverageLimits) {
|
|
7873
|
-
extractorNames = extractorNames.filter((name) => name !== "coverage_limits");
|
|
7874
|
-
}
|
|
7875
|
-
}
|
|
7876
|
-
if (inventoryTypes?.has("endorsement") && !extractorNames.includes("endorsements")) {
|
|
7877
|
-
extractorNames = [...extractorNames, "endorsements"];
|
|
7878
|
-
}
|
|
7879
7400
|
return {
|
|
7880
7401
|
...assignment,
|
|
7881
7402
|
extractorNames
|
|
@@ -8214,6 +7735,18 @@ function createExtractor(config) {
|
|
|
8214
7735
|
return typeof start === "number" && typeof end === "number" && start <= endPage && end >= startPage;
|
|
8215
7736
|
});
|
|
8216
7737
|
}
|
|
7738
|
+
function formatSourceSpanText(spans) {
|
|
7739
|
+
return spans.filter((span) => span.text.trim().length > 0).map((span) => {
|
|
7740
|
+
const page = pageNumberForSpan(span);
|
|
7741
|
+
const label = [
|
|
7742
|
+
page ? `Page ${page}` : void 0,
|
|
7743
|
+
span.sectionId,
|
|
7744
|
+
span.formNumber
|
|
7745
|
+
].filter(Boolean).join(" | ");
|
|
7746
|
+
return label ? `${label}
|
|
7747
|
+
${span.text}` : span.text;
|
|
7748
|
+
}).join("\n\n---\n\n");
|
|
7749
|
+
}
|
|
8217
7750
|
function inferSectionType(title, text) {
|
|
8218
7751
|
const value = `${title} ${text.slice(0, 500)}`.toLowerCase();
|
|
8219
7752
|
if (/\bdefinition|defined terms?\b/.test(value)) return "definition";
|
|
@@ -8250,93 +7783,6 @@ function createExtractor(config) {
|
|
|
8250
7783
|
if (!line) return void 0;
|
|
8251
7784
|
return line.slice(0, 100);
|
|
8252
7785
|
}
|
|
8253
|
-
function buildDeterministicFormInventory(spans, pageCount) {
|
|
8254
|
-
if (spans.length === 0) return void 0;
|
|
8255
|
-
const formPattern = /\b([A-Z]{1,4}\s?\d{2,5}(?:\s?\d{2,4})?|[A-Z]{2,8}-\d{2,8})\b/g;
|
|
8256
|
-
const seen = /* @__PURE__ */ new Map();
|
|
8257
|
-
for (const span of spans) {
|
|
8258
|
-
const page = pageNumberForSpan(span);
|
|
8259
|
-
if (!page) continue;
|
|
8260
|
-
const title = firstHeadingLine(span.text) ?? span.sectionId;
|
|
8261
|
-
const matches = /* @__PURE__ */ new Set([
|
|
8262
|
-
...span.formNumber ? [span.formNumber] : [],
|
|
8263
|
-
...Array.from(span.text.slice(0, 1200).matchAll(formPattern), (match) => match[1].trim())
|
|
8264
|
-
]);
|
|
8265
|
-
for (const formNumber of matches) {
|
|
8266
|
-
const key = `${formNumber}:${title ?? ""}`;
|
|
8267
|
-
const existing = seen.get(key);
|
|
8268
|
-
const formType = inferFormType(title ?? "", span.text);
|
|
8269
|
-
if (existing) {
|
|
8270
|
-
existing.pageStart = Math.min(existing.pageStart ?? page, page);
|
|
8271
|
-
existing.pageEnd = Math.max(existing.pageEnd ?? page, page);
|
|
8272
|
-
continue;
|
|
8273
|
-
}
|
|
8274
|
-
seen.set(key, {
|
|
8275
|
-
formNumber,
|
|
8276
|
-
title,
|
|
8277
|
-
formType,
|
|
8278
|
-
pageStart: Math.min(page, pageCount),
|
|
8279
|
-
pageEnd: Math.min(page, pageCount)
|
|
8280
|
-
});
|
|
8281
|
-
}
|
|
8282
|
-
}
|
|
8283
|
-
const forms = [...seen.values()].sort((a, b) => (a.pageStart ?? 0) - (b.pageStart ?? 0));
|
|
8284
|
-
return forms.length > 0 ? { forms } : void 0;
|
|
8285
|
-
}
|
|
8286
|
-
function inferFormType(title, text) {
|
|
8287
|
-
const value = `${title} ${text.slice(0, 700)}`.toLowerCase();
|
|
8288
|
-
if (/\bdeclarations?|schedule\b/.test(value)) return "declarations";
|
|
8289
|
-
if (/\bendorsement|amendatory|additional insured\b/.test(value)) return "endorsement";
|
|
8290
|
-
if (/\bnotice|department of insurance|complaint|privacy\b/.test(value)) return "notice";
|
|
8291
|
-
if (/\bapplication|questionnaire\b/.test(value)) return "application";
|
|
8292
|
-
if (/\bcoverage|policy form|conditions|exclusions|definitions|causes of loss\b/.test(value)) return "coverage";
|
|
8293
|
-
return "other";
|
|
8294
|
-
}
|
|
8295
|
-
function buildDeterministicPageAssignments(spans, pageCount) {
|
|
8296
|
-
if (spans.length === 0) return [];
|
|
8297
|
-
const pageTexts = /* @__PURE__ */ new Map();
|
|
8298
|
-
for (const span of spans) {
|
|
8299
|
-
const page = pageNumberForSpan(span);
|
|
8300
|
-
if (!page) continue;
|
|
8301
|
-
pageTexts.set(page, [pageTexts.get(page), span.sectionId, span.text].filter(Boolean).join("\n"));
|
|
8302
|
-
}
|
|
8303
|
-
return Array.from({ length: pageCount }, (_, index) => {
|
|
8304
|
-
const page = index + 1;
|
|
8305
|
-
const text = pageTexts.get(page) ?? "";
|
|
8306
|
-
const lower = text.toLowerCase();
|
|
8307
|
-
const extractorNames = [];
|
|
8308
|
-
if (/\bdeclarations?|policy period|named insured|producer|schedule\b/.test(lower)) {
|
|
8309
|
-
extractorNames.push("carrier_info", "named_insured", "declarations");
|
|
8310
|
-
}
|
|
8311
|
-
if (/\blimit|deductible|premium|coinsurance|scheduled amount|blanket\b/.test(lower) && /\$|\b\d{2,}(?:,\d{3})*\b/.test(lower)) {
|
|
8312
|
-
extractorNames.push("coverage_limits");
|
|
8313
|
-
}
|
|
8314
|
-
if (/\bpremium|tax|fee|surcharge\b/.test(lower) && /\$/.test(lower)) extractorNames.push("premium_breakdown");
|
|
8315
|
-
if (/\bendorsement|additional insured|amendatory\b/.test(lower)) extractorNames.push("endorsements");
|
|
8316
|
-
if (/\bexclusion|not covered|does not apply\b/.test(lower)) extractorNames.push("exclusions");
|
|
8317
|
-
if (/\bcondition|duties in the event|loss condition|general condition\b/.test(lower)) extractorNames.push("conditions");
|
|
8318
|
-
if (/\bdefinition|defined terms?\b/.test(lower)) extractorNames.push("definitions");
|
|
8319
|
-
if (/\bcovered cause|covered peril|cause of loss|perils insured\b/.test(lower)) extractorNames.push("covered_reasons");
|
|
8320
|
-
if (textIncludesSupplementarySignal(text)) extractorNames.push("supplementary");
|
|
8321
|
-
if (extractorNames.length === 0 && text.trim().length > 180) extractorNames.push("sections");
|
|
8322
|
-
return {
|
|
8323
|
-
localPageNumber: page,
|
|
8324
|
-
extractorNames: [...new Set(extractorNames)],
|
|
8325
|
-
pageRole: inferPageRole(lower),
|
|
8326
|
-
hasScheduleValues: /\$|\b\d{2,}(?:,\d{3})*\b/.test(lower) && /\blimit|deductible|premium|schedule|class|location\b/.test(lower),
|
|
8327
|
-
confidence: text.trim().length > 0 ? 0.8 : 0,
|
|
8328
|
-
notes: "Deterministic source-span page assignment"
|
|
8329
|
-
};
|
|
8330
|
-
});
|
|
8331
|
-
}
|
|
8332
|
-
function inferPageRole(lowerText) {
|
|
8333
|
-
if (/\bdeclarations?|schedule\b/.test(lowerText)) return "declarations_schedule";
|
|
8334
|
-
if (/\bendorsement\b/.test(lowerText)) return "endorsement_form";
|
|
8335
|
-
if (/\bexclusion|condition\b/.test(lowerText)) return "condition_exclusion_form";
|
|
8336
|
-
if (/\bnotice|department of insurance|complaint\b/.test(lowerText)) return "supplementary";
|
|
8337
|
-
if (lowerText.trim()) return "policy_form";
|
|
8338
|
-
return "other";
|
|
8339
|
-
}
|
|
8340
7786
|
function shouldRunLlmReview(mode, report, sourceSpansAvailable) {
|
|
8341
7787
|
if (mode === "skip" || maxReviewRounds <= 0) return false;
|
|
8342
7788
|
if (mode === "always") return true;
|
|
@@ -8557,21 +8003,28 @@ function createExtractor(config) {
|
|
|
8557
8003
|
return promise;
|
|
8558
8004
|
}
|
|
8559
8005
|
async function getPageRangeText(startPage, endPage) {
|
|
8560
|
-
|
|
8006
|
+
if (doclingDocument) return getDoclingPageRangeText(doclingDocument, startPage, endPage);
|
|
8007
|
+
return formatSourceSpanText(spansForPageRange(sourceSpans, startPage, endPage));
|
|
8561
8008
|
}
|
|
8562
8009
|
function withFullDocumentTextContext(prompt) {
|
|
8563
|
-
if (
|
|
8564
|
-
return `${prompt}
|
|
8010
|
+
if (doclingDocument) return `${prompt}
|
|
8565
8011
|
|
|
8566
8012
|
DOCLING DOCUMENT TEXT:
|
|
8567
8013
|
${doclingDocument.fullText}`;
|
|
8014
|
+
const sourceText = formatSourceSpanText(sourceSpans);
|
|
8015
|
+
if (!sourceText) return prompt;
|
|
8016
|
+
return `${prompt}
|
|
8017
|
+
|
|
8018
|
+
SOURCE SPAN DOCUMENT TEXT:
|
|
8019
|
+
${sourceText}`;
|
|
8568
8020
|
}
|
|
8569
8021
|
function withPageRangeTextContext(prompt, startPage, endPage, pageText) {
|
|
8570
|
-
if (!
|
|
8022
|
+
if (!pageText) return prompt;
|
|
8023
|
+
const label = doclingDocument ? "DOCLING DOCUMENT" : "SOURCE SPAN DOCUMENT";
|
|
8571
8024
|
return `${prompt}
|
|
8572
8025
|
|
|
8573
|
-
|
|
8574
|
-
${pageText
|
|
8026
|
+
${label} PAGES ${startPage}-${endPage}:
|
|
8027
|
+
${pageText}`;
|
|
8575
8028
|
}
|
|
8576
8029
|
let classifyResult;
|
|
8577
8030
|
if (resumed?.classifyResult && pipelineCtx.isPhaseComplete("classify")) {
|
|
@@ -8628,17 +8081,6 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
8628
8081
|
formInventory = resumed.formInventory;
|
|
8629
8082
|
memory.set("form_inventory", formInventory);
|
|
8630
8083
|
onProgress?.("Resuming from checkpoint (form inventory complete)...");
|
|
8631
|
-
} else if (sourceSpans.length > 0) {
|
|
8632
|
-
formInventory = buildDeterministicFormInventory(sourceSpans, pageCount) ?? { forms: [] };
|
|
8633
|
-
onProgress?.(`Built deterministic form inventory for ${primaryType} ${documentType}.`);
|
|
8634
|
-
memory.set("form_inventory", formInventory);
|
|
8635
|
-
await pipelineCtx.save("form_inventory", {
|
|
8636
|
-
id,
|
|
8637
|
-
pageCount,
|
|
8638
|
-
classifyResult,
|
|
8639
|
-
formInventory,
|
|
8640
|
-
memory: Object.fromEntries(memory)
|
|
8641
|
-
});
|
|
8642
8084
|
} else {
|
|
8643
8085
|
onProgress?.(`Building form inventory for ${primaryType} ${documentType}...`);
|
|
8644
8086
|
const budget = resolveBudget("extraction_form_inventory", 2048);
|
|
@@ -8679,20 +8121,6 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
8679
8121
|
if (resumed?.pageAssignments && pipelineCtx.isPhaseComplete("page_map")) {
|
|
8680
8122
|
pageAssignments = resumed.pageAssignments;
|
|
8681
8123
|
onProgress?.("Resuming from checkpoint (page map complete)...");
|
|
8682
|
-
} else if (sourceSpans.length > 0) {
|
|
8683
|
-
onProgress?.(`Mapping document pages from source spans for ${primaryType} ${documentType}...`);
|
|
8684
|
-
pageAssignments = normalizePageAssignments(
|
|
8685
|
-
buildDeterministicPageAssignments(sourceSpans, pageCount),
|
|
8686
|
-
formInventory
|
|
8687
|
-
);
|
|
8688
|
-
await pipelineCtx.save("page_map", {
|
|
8689
|
-
id,
|
|
8690
|
-
pageCount,
|
|
8691
|
-
classifyResult,
|
|
8692
|
-
formInventory,
|
|
8693
|
-
pageAssignments,
|
|
8694
|
-
memory: Object.fromEntries(memory)
|
|
8695
|
-
});
|
|
8696
8124
|
} else {
|
|
8697
8125
|
onProgress?.(`Mapping document pages for ${primaryType} ${documentType}...`);
|
|
8698
8126
|
const chunkSize = 8;
|
|
@@ -8709,7 +8137,7 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
8709
8137
|
pageMapChunks.map(
|
|
8710
8138
|
({ startPage, endPage }) => pageMapLimit(async () => {
|
|
8711
8139
|
const pagesPdf = doclingDocument ? void 0 : await getPageRangePdf(startPage, endPage);
|
|
8712
|
-
const pagesText =
|
|
8140
|
+
const pagesText = await getPageRangeText(startPage, endPage);
|
|
8713
8141
|
const budget = resolveBudget("extraction_page_map", 2048);
|
|
8714
8142
|
const startedAt = Date.now();
|
|
8715
8143
|
const mapResponse = await safeGenerateObject(
|
|
@@ -8816,7 +8244,7 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
8816
8244
|
completedPageRangePdfCache,
|
|
8817
8245
|
getPageRangePdf,
|
|
8818
8246
|
convertPdfToImages ? getPageImages : void 0,
|
|
8819
|
-
doclingDocument ? getPageRangeText : void 0
|
|
8247
|
+
sourceSpans.length > 0 || doclingDocument ? getPageRangeText : void 0
|
|
8820
8248
|
);
|
|
8821
8249
|
})
|
|
8822
8250
|
)
|
|
@@ -8849,7 +8277,7 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
8849
8277
|
pageRangeCache: completedPageRangePdfCache,
|
|
8850
8278
|
getPageRangePdf,
|
|
8851
8279
|
getPageImages: convertPdfToImages ? getPageImages : void 0,
|
|
8852
|
-
getPageRangeText: doclingDocument ? getPageRangeText : void 0
|
|
8280
|
+
getPageRangeText: sourceSpans.length > 0 || doclingDocument ? getPageRangeText : void 0
|
|
8853
8281
|
});
|
|
8854
8282
|
trackUsage(supplementaryResult.usage, {
|
|
8855
8283
|
taskKind: "extraction_focused",
|
|
@@ -8885,7 +8313,7 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
8885
8313
|
concurrency,
|
|
8886
8314
|
getPageRangePdf,
|
|
8887
8315
|
getPageImages: convertPdfToImages ? getPageImages : void 0,
|
|
8888
|
-
getPageRangeText: doclingDocument ? getPageRangeText : void 0,
|
|
8316
|
+
getPageRangeText: sourceSpans.length > 0 || doclingDocument ? getPageRangeText : void 0,
|
|
8889
8317
|
providerOptions: activeProviderOptions,
|
|
8890
8318
|
modelCapabilities,
|
|
8891
8319
|
modelBudgetConstraints,
|
|
@@ -8981,7 +8409,7 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
8981
8409
|
completedPageRangePdfCache,
|
|
8982
8410
|
getPageRangePdf,
|
|
8983
8411
|
convertPdfToImages ? getPageImages : void 0,
|
|
8984
|
-
doclingDocument ? getPageRangeText : void 0
|
|
8412
|
+
sourceSpans.length > 0 || doclingDocument ? getPageRangeText : void 0
|
|
8985
8413
|
);
|
|
8986
8414
|
})
|
|
8987
8415
|
)
|