@claritylabs/cl-sdk 3.0.21 → 3.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.d.mts +155 -1
- package/dist/index.d.ts +155 -1
- package/dist/index.js +367 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +366 -14
- package/dist/index.mjs.map +1 -1
- package/dist/storage-sqlite.js +24 -0
- package/dist/storage-sqlite.js.map +1 -1
- package/dist/storage-sqlite.mjs +24 -0
- package/dist/storage-sqlite.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2045,14 +2045,38 @@ var SourceBackedValueSchema = z20.object({
|
|
|
2045
2045
|
sourceNodeIds: z20.array(z20.string().min(1)).default([]),
|
|
2046
2046
|
sourceSpanIds: z20.array(z20.string().min(1)).default([])
|
|
2047
2047
|
});
|
|
2048
|
+
var OperationalCoverageTermSchema = z20.object({
|
|
2049
|
+
kind: z20.enum([
|
|
2050
|
+
"each_claim_limit",
|
|
2051
|
+
"each_occurrence_limit",
|
|
2052
|
+
"each_loss_limit",
|
|
2053
|
+
"aggregate_limit",
|
|
2054
|
+
"sublimit",
|
|
2055
|
+
"retention",
|
|
2056
|
+
"deductible",
|
|
2057
|
+
"retroactive_date",
|
|
2058
|
+
"premium",
|
|
2059
|
+
"other"
|
|
2060
|
+
]).default("other"),
|
|
2061
|
+
label: z20.string(),
|
|
2062
|
+
value: z20.string(),
|
|
2063
|
+
amount: z20.number().optional(),
|
|
2064
|
+
appliesTo: z20.string().optional(),
|
|
2065
|
+
sourceNodeIds: z20.array(z20.string().min(1)).default([]),
|
|
2066
|
+
sourceSpanIds: z20.array(z20.string().min(1)).default([])
|
|
2067
|
+
});
|
|
2048
2068
|
var OperationalCoverageLineSchema = z20.object({
|
|
2049
2069
|
name: z20.string(),
|
|
2050
2070
|
coverageCode: z20.string().optional(),
|
|
2051
2071
|
limit: z20.string().optional(),
|
|
2052
2072
|
deductible: z20.string().optional(),
|
|
2053
2073
|
premium: z20.string().optional(),
|
|
2074
|
+
retroactiveDate: z20.string().optional(),
|
|
2054
2075
|
formNumber: z20.string().optional(),
|
|
2055
2076
|
sectionRef: z20.string().optional(),
|
|
2077
|
+
coverageOrigin: z20.enum(["core", "endorsement"]).optional(),
|
|
2078
|
+
endorsementNumber: z20.string().optional(),
|
|
2079
|
+
limits: z20.array(OperationalCoverageTermSchema).default([]),
|
|
2056
2080
|
sourceNodeIds: z20.array(z20.string().min(1)).default([]),
|
|
2057
2081
|
sourceSpanIds: z20.array(z20.string().min(1)).default([])
|
|
2058
2082
|
});
|
|
@@ -2995,14 +3019,265 @@ function deductibleFromText(text) {
|
|
|
2995
3019
|
function premiumFromText(text) {
|
|
2996
3020
|
return moneyValue(text.match(/\b(?:premium|total premium|total cost|amount due)\s*:?\s*(\$?\d[\d,]*(?:\.\d{2})?)/i)?.[1]);
|
|
2997
3021
|
}
|
|
3022
|
+
function moneyAmount(value) {
|
|
3023
|
+
const match = value?.match(/\$?\s*([0-9][0-9,]*(?:\.\d+)?)/);
|
|
3024
|
+
if (!match) return void 0;
|
|
3025
|
+
const amount = Number(match[1].replace(/,/g, ""));
|
|
3026
|
+
return Number.isFinite(amount) ? amount : void 0;
|
|
3027
|
+
}
|
|
3028
|
+
function normalizeLabel(value) {
|
|
3029
|
+
return normalizeWhitespace3(value ?? "").toLowerCase();
|
|
3030
|
+
}
|
|
3031
|
+
var OPERATIONAL_COVERAGE_TERM_KINDS = /* @__PURE__ */ new Set([
|
|
3032
|
+
"each_claim_limit",
|
|
3033
|
+
"each_occurrence_limit",
|
|
3034
|
+
"each_loss_limit",
|
|
3035
|
+
"aggregate_limit",
|
|
3036
|
+
"sublimit",
|
|
3037
|
+
"retention",
|
|
3038
|
+
"deductible",
|
|
3039
|
+
"retroactive_date",
|
|
3040
|
+
"premium",
|
|
3041
|
+
"other"
|
|
3042
|
+
]);
|
|
3043
|
+
function termKind(label, value) {
|
|
3044
|
+
const text = normalizeLabel(`${label} ${value}`);
|
|
3045
|
+
if (/\bretroactive\b/.test(text)) return "retroactive_date";
|
|
3046
|
+
if (/\b(self[-\s]?insured retention|retention|sir)\b/.test(text)) return "retention";
|
|
3047
|
+
if (/\bdeductible\b/.test(text)) return "deductible";
|
|
3048
|
+
if (/\bpremium\b/.test(text)) return "premium";
|
|
3049
|
+
if (/\bsub[-\s]?limit\b/.test(text)) return "sublimit";
|
|
3050
|
+
if (/\baggregate\b/.test(text)) return "aggregate_limit";
|
|
3051
|
+
if (/\beach\s+claim|per\s+claim\b/.test(text)) return "each_claim_limit";
|
|
3052
|
+
if (/\beach\s+occurrence|per\s+occurrence\b/.test(text)) return "each_occurrence_limit";
|
|
3053
|
+
if (/\beach\s+loss|per\s+loss\b/.test(text)) return "each_loss_limit";
|
|
3054
|
+
if (/\blimit\b/.test(text)) return "other";
|
|
3055
|
+
return "other";
|
|
3056
|
+
}
|
|
3057
|
+
function normalizeTermKind(value, label, termValue) {
|
|
3058
|
+
return typeof value === "string" && OPERATIONAL_COVERAGE_TERM_KINDS.has(value) ? value : termKind(label, termValue);
|
|
3059
|
+
}
|
|
3060
|
+
function isValueCell(label, value) {
|
|
3061
|
+
const normalizedLabel = normalizeLabel(label);
|
|
3062
|
+
const normalizedValue = normalizeLabel(value);
|
|
3063
|
+
if (!value || normalizedValue === "\u2014") return false;
|
|
3064
|
+
if (/\b(policy\s*(number|no|#)|named insured|insured|carrier|company|broker|producer|agent|coverage|coverage part|description|item|name|form|source)\b/.test(normalizedLabel)) {
|
|
3065
|
+
return false;
|
|
3066
|
+
}
|
|
3067
|
+
return /\b(limit|aggregate|retention|deductible|sir|retroactive|premium|amount)\b/.test(normalizedLabel) || moneyAmount(value) !== void 0 || /\b(full prior acts|none|included|not included|as stated)\b/.test(normalizedValue);
|
|
3068
|
+
}
|
|
3069
|
+
function isNameCell(label, value) {
|
|
3070
|
+
const normalizedLabel = normalizeLabel(label);
|
|
3071
|
+
const normalizedValue = normalizeLabel(value);
|
|
3072
|
+
if (!value || moneyAmount(value) !== void 0) return false;
|
|
3073
|
+
if (/\b(coverage|coverage part|insuring agreement|description|item|name)\b/.test(normalizedLabel)) {
|
|
3074
|
+
return true;
|
|
3075
|
+
}
|
|
3076
|
+
if (/^column\s+\d+$/.test(normalizedLabel) && /\b(coverage|sub[-\s]?limit|liability|expense|part\s+[a-z])\b/.test(normalizedValue)) {
|
|
3077
|
+
return true;
|
|
3078
|
+
}
|
|
3079
|
+
return false;
|
|
3080
|
+
}
|
|
3081
|
+
function childMap(nodes) {
|
|
3082
|
+
const children = /* @__PURE__ */ new Map();
|
|
3083
|
+
for (const node of nodes) {
|
|
3084
|
+
const group = children.get(node.parentId) ?? [];
|
|
3085
|
+
group.push(node);
|
|
3086
|
+
children.set(node.parentId, group);
|
|
3087
|
+
}
|
|
3088
|
+
for (const group of children.values()) group.sort((left, right) => left.order - right.order);
|
|
3089
|
+
return children;
|
|
3090
|
+
}
|
|
3091
|
+
function cellRows(row, children) {
|
|
3092
|
+
return (children.get(row.id) ?? []).filter((child) => child.kind === "table_cell").map((cell) => ({
|
|
3093
|
+
label: cleanValue(cell.title) ?? "Value",
|
|
3094
|
+
value: cleanValue(cell.textExcerpt ?? cell.description ?? cell.title) ?? "",
|
|
3095
|
+
node: cell
|
|
3096
|
+
})).filter((cell) => cell.value);
|
|
3097
|
+
}
|
|
3098
|
+
function directChildren(parent, children) {
|
|
3099
|
+
return children.get(parent.id) ?? [];
|
|
3100
|
+
}
|
|
3101
|
+
function descendants(parent, children) {
|
|
3102
|
+
const stack = [...directChildren(parent, children)];
|
|
3103
|
+
const result = [];
|
|
3104
|
+
while (stack.length > 0) {
|
|
3105
|
+
const node = stack.shift();
|
|
3106
|
+
result.push(node);
|
|
3107
|
+
stack.unshift(...directChildren(node, children));
|
|
3108
|
+
}
|
|
3109
|
+
return result;
|
|
3110
|
+
}
|
|
3111
|
+
function ancestry(node, byId) {
|
|
3112
|
+
const result = [];
|
|
3113
|
+
let current = node.parentId ? byId.get(node.parentId) : void 0;
|
|
3114
|
+
while (current) {
|
|
3115
|
+
result.push(current);
|
|
3116
|
+
current = current.parentId ? byId.get(current.parentId) : void 0;
|
|
3117
|
+
}
|
|
3118
|
+
return result;
|
|
3119
|
+
}
|
|
3120
|
+
function endorsementAncestor(node, byId) {
|
|
3121
|
+
return ancestry(node, byId).find((ancestor) => ancestor.kind === "endorsement");
|
|
3122
|
+
}
|
|
3123
|
+
function endorsementNumberFrom(value) {
|
|
3124
|
+
return cleanValue(value?.match(/\bendorsement\s+no\.?\s*([0-9A-Z-]+)/i)?.[1]);
|
|
3125
|
+
}
|
|
3126
|
+
function sourceIds(nodes) {
|
|
3127
|
+
return {
|
|
3128
|
+
sourceNodeIds: [...new Set(nodes.map((node) => node.id))],
|
|
3129
|
+
sourceSpanIds: [...new Set(nodes.flatMap((node) => node.sourceSpanIds))]
|
|
3130
|
+
};
|
|
3131
|
+
}
|
|
3132
|
+
function termFromCell(params) {
|
|
3133
|
+
const value = cleanValue(params.value);
|
|
3134
|
+
if (!value) return void 0;
|
|
3135
|
+
const nodes = [params.row, params.cell].filter((node) => Boolean(node));
|
|
3136
|
+
return {
|
|
3137
|
+
kind: termKind(params.label, value),
|
|
3138
|
+
label: params.label,
|
|
3139
|
+
value,
|
|
3140
|
+
...moneyAmount(value) !== void 0 ? { amount: moneyAmount(value) } : {},
|
|
3141
|
+
...params.appliesTo ? { appliesTo: params.appliesTo } : {},
|
|
3142
|
+
...sourceIds(nodes)
|
|
3143
|
+
};
|
|
3144
|
+
}
|
|
3145
|
+
function termsFromRow(row, children) {
|
|
3146
|
+
const cells = cellRows(row, children);
|
|
3147
|
+
if (cells.length > 0) {
|
|
3148
|
+
return cells.filter((cell) => isValueCell(cell.label, cell.value)).map((cell) => termFromCell({ row, cell: cell.node, label: cell.label, value: cell.value })).filter((term) => Boolean(term));
|
|
3149
|
+
}
|
|
3150
|
+
const text = normalizeWhitespace3(row.textExcerpt ?? row.description ?? nodeText(row));
|
|
3151
|
+
const terms = [];
|
|
3152
|
+
for (const part of text.split(/\s+\|\s+/)) {
|
|
3153
|
+
const match = part.match(/^([^:]{2,80}):\s*(.+)$/);
|
|
3154
|
+
if (!match) continue;
|
|
3155
|
+
if (!isValueCell(match[1], match[2])) continue;
|
|
3156
|
+
const term = termFromCell({ row, label: cleanValue(match[1]) ?? "Value", value: match[2] });
|
|
3157
|
+
if (term) terms.push(term);
|
|
3158
|
+
}
|
|
3159
|
+
if (terms.length === 0) {
|
|
3160
|
+
const limit = limitFromText(text);
|
|
3161
|
+
if (limit) {
|
|
3162
|
+
const term = termFromCell({ row, label: "Limit", value: limit });
|
|
3163
|
+
if (term) terms.push(term);
|
|
3164
|
+
}
|
|
3165
|
+
const deductible = deductibleFromText(text);
|
|
3166
|
+
if (deductible) {
|
|
3167
|
+
const term = termFromCell({ row, label: "Deductible", value: deductible });
|
|
3168
|
+
if (term) terms.push(term);
|
|
3169
|
+
}
|
|
3170
|
+
}
|
|
3171
|
+
return terms;
|
|
3172
|
+
}
|
|
3173
|
+
function nameFromRow(row, children) {
|
|
3174
|
+
const cells = cellRows(row, children);
|
|
3175
|
+
const named = cells.find((cell) => isNameCell(cell.label, cell.value));
|
|
3176
|
+
if (named) return cleanValue(named.value);
|
|
3177
|
+
return coverageNameFromRow(nodeText(row));
|
|
3178
|
+
}
|
|
3179
|
+
function legacyLimit(terms) {
|
|
3180
|
+
return terms.find(
|
|
3181
|
+
(term) => ["each_claim_limit", "each_occurrence_limit", "each_loss_limit", "aggregate_limit", "sublimit", "other"].includes(term.kind)
|
|
3182
|
+
)?.value;
|
|
3183
|
+
}
|
|
3184
|
+
function legacyDeductible(terms) {
|
|
3185
|
+
return terms.find((term) => term.kind === "deductible" || term.kind === "retention")?.value;
|
|
3186
|
+
}
|
|
3187
|
+
function legacyPremium(terms) {
|
|
3188
|
+
return terms.find((term) => term.kind === "premium")?.value;
|
|
3189
|
+
}
|
|
3190
|
+
function retroDate(terms) {
|
|
3191
|
+
return terms.find((term) => term.kind === "retroactive_date")?.value;
|
|
3192
|
+
}
|
|
3193
|
+
function uniqueTerms(terms) {
|
|
3194
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3195
|
+
const result = [];
|
|
3196
|
+
for (const term of terms) {
|
|
3197
|
+
const key = [term.kind, term.label.toLowerCase(), term.value.toLowerCase(), term.appliesTo ?? ""].join("|");
|
|
3198
|
+
if (seen.has(key)) continue;
|
|
3199
|
+
seen.add(key);
|
|
3200
|
+
result.push(term);
|
|
3201
|
+
}
|
|
3202
|
+
return result;
|
|
3203
|
+
}
|
|
3204
|
+
function coverageFromTableRow(row, children, byId) {
|
|
3205
|
+
if (row.metadata?.isHeader === true || row.metadata?.isHeader === "true") return void 0;
|
|
3206
|
+
const name = nameFromRow(row, children);
|
|
3207
|
+
const terms = uniqueTerms(termsFromRow(row, children));
|
|
3208
|
+
if (!name || terms.length === 0) return void 0;
|
|
3209
|
+
const ids = sourceIds([row, ...directChildren(row, children)]);
|
|
3210
|
+
const endorsement = endorsementAncestor(row, byId);
|
|
3211
|
+
return {
|
|
3212
|
+
name,
|
|
3213
|
+
limit: legacyLimit(terms),
|
|
3214
|
+
deductible: legacyDeductible(terms),
|
|
3215
|
+
premium: legacyPremium(terms),
|
|
3216
|
+
retroactiveDate: retroDate(terms),
|
|
3217
|
+
formNumber: typeof row.metadata?.formNumber === "string" ? row.metadata.formNumber : void 0,
|
|
3218
|
+
sectionRef: endorsement?.title,
|
|
3219
|
+
coverageOrigin: endorsement ? "endorsement" : "core",
|
|
3220
|
+
endorsementNumber: endorsementNumberFrom(endorsement?.title),
|
|
3221
|
+
limits: terms,
|
|
3222
|
+
...ids
|
|
3223
|
+
};
|
|
3224
|
+
}
|
|
3225
|
+
function coverageFromEndorsement(endorsement, children) {
|
|
3226
|
+
const rows = descendants(endorsement, children).filter((node) => node.kind === "table_row");
|
|
3227
|
+
const terms = uniqueTerms(rows.flatMap(
|
|
3228
|
+
(row) => termsFromRow(row, children).map((term) => {
|
|
3229
|
+
const appliesTo = nameFromRow(row, children);
|
|
3230
|
+
return appliesTo && !/^(each claim limit|aggregate limit|retroactive date)$/i.test(appliesTo) ? { ...term, appliesTo } : term;
|
|
3231
|
+
})
|
|
3232
|
+
));
|
|
3233
|
+
if (terms.length === 0) return void 0;
|
|
3234
|
+
const ids = sourceIds([endorsement, ...rows, ...rows.flatMap((row) => directChildren(row, children))]);
|
|
3235
|
+
return {
|
|
3236
|
+
name: endorsement.title,
|
|
3237
|
+
limit: legacyLimit(terms),
|
|
3238
|
+
deductible: legacyDeductible(terms),
|
|
3239
|
+
premium: legacyPremium(terms),
|
|
3240
|
+
retroactiveDate: retroDate(terms),
|
|
3241
|
+
formNumber: typeof endorsement.metadata?.formNumber === "string" ? endorsement.metadata.formNumber : void 0,
|
|
3242
|
+
sectionRef: endorsement.title,
|
|
3243
|
+
coverageOrigin: "endorsement",
|
|
3244
|
+
endorsementNumber: endorsementNumberFrom(endorsement.title),
|
|
3245
|
+
limits: terms,
|
|
3246
|
+
...ids
|
|
3247
|
+
};
|
|
3248
|
+
}
|
|
2998
3249
|
function buildCoverages(nodes) {
|
|
3250
|
+
const children = childMap(nodes);
|
|
3251
|
+
const byId = new Map(nodes.map((node) => [node.id, node]));
|
|
3252
|
+
const coverages = [];
|
|
3253
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3254
|
+
for (const endorsement of nodes.filter((node) => node.kind === "endorsement")) {
|
|
3255
|
+
const coverage = coverageFromEndorsement(endorsement, children);
|
|
3256
|
+
if (!coverage) continue;
|
|
3257
|
+
const key = [coverage.name.toLowerCase(), coverage.sourceNodeIds.join(",")].join("|");
|
|
3258
|
+
if (seen.has(key)) continue;
|
|
3259
|
+
seen.add(key);
|
|
3260
|
+
coverages.push(coverage);
|
|
3261
|
+
}
|
|
2999
3262
|
const rows = nodes.filter((node) => {
|
|
3000
3263
|
const text = nodeText(node);
|
|
3001
|
-
return (node.kind === "table_row" || node.kind === "schedule" || node.kind === "text") && /\b(coverage|limit|deductible|aggregate|occurrence|liability|premium)\b/i.test(text);
|
|
3264
|
+
return (node.kind === "table_row" || node.kind === "schedule" || node.kind === "text") && /\b(coverage|limit|deductible|aggregate|occurrence|liability|premium|retroactive|retention)\b/i.test(text);
|
|
3002
3265
|
});
|
|
3003
|
-
const coverages = [];
|
|
3004
|
-
const seen = /* @__PURE__ */ new Set();
|
|
3005
3266
|
for (const row of rows) {
|
|
3267
|
+
if (endorsementAncestor(row, byId)) continue;
|
|
3268
|
+
const structured = row.kind === "table_row" ? coverageFromTableRow(row, children, byId) : void 0;
|
|
3269
|
+
if (structured) {
|
|
3270
|
+
const key2 = [
|
|
3271
|
+
structured.name.toLowerCase(),
|
|
3272
|
+
structured.limits.map((term) => `${term.kind}:${term.value}`).join(","),
|
|
3273
|
+
structured.sourceNodeIds.join(",")
|
|
3274
|
+
].join("|");
|
|
3275
|
+
if (seen.has(key2)) continue;
|
|
3276
|
+
seen.add(key2);
|
|
3277
|
+
coverages.push(structured);
|
|
3278
|
+
if (coverages.length >= 60) break;
|
|
3279
|
+
continue;
|
|
3280
|
+
}
|
|
3006
3281
|
const text = nodeText(row);
|
|
3007
3282
|
const name = coverageNameFromRow(text);
|
|
3008
3283
|
const limit = limitFromText(text);
|
|
@@ -3018,6 +3293,8 @@ function buildCoverages(nodes) {
|
|
|
3018
3293
|
deductible,
|
|
3019
3294
|
premium,
|
|
3020
3295
|
formNumber: typeof row.metadata?.formNumber === "string" ? row.metadata.formNumber : void 0,
|
|
3296
|
+
coverageOrigin: "core",
|
|
3297
|
+
limits: [],
|
|
3021
3298
|
sourceNodeIds: [row.id],
|
|
3022
3299
|
sourceSpanIds: row.sourceSpanIds
|
|
3023
3300
|
});
|
|
@@ -3159,11 +3436,33 @@ function mergeOperationalProfile(base, candidate, validNodeIds, validSpanIds) {
|
|
|
3159
3436
|
sourceSpanIds
|
|
3160
3437
|
};
|
|
3161
3438
|
};
|
|
3162
|
-
const coverages = Array.isArray(candidate.coverages) ? candidate.coverages.map((coverage) =>
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3439
|
+
const coverages = Array.isArray(candidate.coverages) ? candidate.coverages.map((coverage) => {
|
|
3440
|
+
const record = coverage;
|
|
3441
|
+
const limits = Array.isArray(record.limits) ? record.limits.filter(
|
|
3442
|
+
(term) => Boolean(term) && typeof term === "object" && !Array.isArray(term)
|
|
3443
|
+
).flatMap((term) => {
|
|
3444
|
+
const label = typeof term.label === "string" ? cleanValue(term.label) : void 0;
|
|
3445
|
+
const value = typeof term.value === "string" ? cleanValue(term.value) : void 0;
|
|
3446
|
+
const sourceNodeIds = keepIds(term.sourceNodeIds, validNodeIds);
|
|
3447
|
+
const sourceSpanIds = keepIds(term.sourceSpanIds, validSpanIds);
|
|
3448
|
+
if (!label || !value || sourceNodeIds.length === 0 && sourceSpanIds.length === 0) return [];
|
|
3449
|
+
return [{
|
|
3450
|
+
kind: normalizeTermKind(term.kind, label, value),
|
|
3451
|
+
label,
|
|
3452
|
+
value,
|
|
3453
|
+
amount: typeof term.amount === "number" && Number.isFinite(term.amount) ? term.amount : void 0,
|
|
3454
|
+
appliesTo: typeof term.appliesTo === "string" ? term.appliesTo : void 0,
|
|
3455
|
+
sourceNodeIds,
|
|
3456
|
+
sourceSpanIds
|
|
3457
|
+
}];
|
|
3458
|
+
}) : [];
|
|
3459
|
+
return {
|
|
3460
|
+
...coverage,
|
|
3461
|
+
limits,
|
|
3462
|
+
sourceNodeIds: keepIds(record.sourceNodeIds, validNodeIds),
|
|
3463
|
+
sourceSpanIds: keepIds(record.sourceSpanIds, validSpanIds)
|
|
3464
|
+
};
|
|
3465
|
+
}).filter((coverage) => coverage.name && (coverage.sourceNodeIds.length > 0 || coverage.sourceSpanIds.length > 0)) : base.coverages;
|
|
3167
3466
|
return PolicyOperationalProfileSchema.parse({
|
|
3168
3467
|
...base,
|
|
3169
3468
|
documentType: candidate.documentType === "quote" ? "quote" : candidate.documentType === "policy" ? "policy" : base.documentType,
|
|
@@ -9173,8 +9472,31 @@ var OperationalProfilePromptSchema = z41.object({
|
|
|
9173
9472
|
limit: z41.string().optional(),
|
|
9174
9473
|
deductible: z41.string().optional(),
|
|
9175
9474
|
premium: z41.string().optional(),
|
|
9475
|
+
retroactiveDate: z41.string().optional(),
|
|
9176
9476
|
formNumber: z41.string().optional(),
|
|
9177
9477
|
sectionRef: z41.string().optional(),
|
|
9478
|
+
coverageOrigin: z41.enum(["core", "endorsement"]).optional(),
|
|
9479
|
+
endorsementNumber: z41.string().optional(),
|
|
9480
|
+
limits: z41.array(z41.object({
|
|
9481
|
+
kind: z41.enum([
|
|
9482
|
+
"each_claim_limit",
|
|
9483
|
+
"each_occurrence_limit",
|
|
9484
|
+
"each_loss_limit",
|
|
9485
|
+
"aggregate_limit",
|
|
9486
|
+
"sublimit",
|
|
9487
|
+
"retention",
|
|
9488
|
+
"deductible",
|
|
9489
|
+
"retroactive_date",
|
|
9490
|
+
"premium",
|
|
9491
|
+
"other"
|
|
9492
|
+
]).optional(),
|
|
9493
|
+
label: z41.string(),
|
|
9494
|
+
value: z41.string(),
|
|
9495
|
+
amount: z41.number().optional(),
|
|
9496
|
+
appliesTo: z41.string().optional(),
|
|
9497
|
+
sourceNodeIds: z41.array(z41.string()),
|
|
9498
|
+
sourceSpanIds: z41.array(z41.string())
|
|
9499
|
+
})).optional(),
|
|
9178
9500
|
sourceNodeIds: z41.array(z41.string()),
|
|
9179
9501
|
sourceSpanIds: z41.array(z41.string())
|
|
9180
9502
|
})).optional(),
|
|
@@ -9328,6 +9650,25 @@ function pageTitleFromText(text, fallback) {
|
|
|
9328
9650
|
if (firstSentence && firstSentence.length <= 120) return firstSentence.replace(/[.]$/, "");
|
|
9329
9651
|
return fallback;
|
|
9330
9652
|
}
|
|
9653
|
+
function pageHeadingTitleFromText(text, fallback) {
|
|
9654
|
+
const normalized = cleanText(text, "");
|
|
9655
|
+
const headingText = normalized.replace(/^page\s+\d+\s*(?:\|\s*page\s*\|\s*page\s+\d+\s*\|?)?/i, "").slice(0, 700);
|
|
9656
|
+
const patterns = [
|
|
9657
|
+
/\bIMPORTANT NOTICE\s+[—-]\s+HOW TO REPORT A CLAIM\b/i,
|
|
9658
|
+
/\bPRIVACY NOTICE TO POLICYHOLDERS\b/i,
|
|
9659
|
+
/\bOFAC ADVISORY NOTICE\b/i,
|
|
9660
|
+
/\bTERRORISM RISK INSURANCE ACT\s*\(TRIA\)\s*DISCLOSURE AND REJECTION\b/i,
|
|
9661
|
+
/\bDECLARATIONS PAGE\b/i,
|
|
9662
|
+
/\bTECHNOLOGY ERRORS?\s*&\s*OMISSIONS AND CYBER LIABILITY INSURANCE POLICY\b/i,
|
|
9663
|
+
/\bTRADE OR ECONOMIC SANCTIONS LIMITATION\b/i,
|
|
9664
|
+
/\bFORMS? AND ENDORSEMENTS\b/i
|
|
9665
|
+
];
|
|
9666
|
+
for (const pattern of patterns) {
|
|
9667
|
+
const match = headingText.match(pattern)?.[0];
|
|
9668
|
+
if (match) return cleanText(match, fallback);
|
|
9669
|
+
}
|
|
9670
|
+
return fallback;
|
|
9671
|
+
}
|
|
9331
9672
|
function pageFormTypeFromText(text) {
|
|
9332
9673
|
if (/\b(declarations?\s+page|declarations?\s+schedule)\b/i.test(text)) return "declarations";
|
|
9333
9674
|
if (/\b(endorsement\s+(?:no\.?|number|#)|this endorsement changes the policy|[A-Z]{2,}-END\s+\d{2,})\b/i.test(text)) return "endorsement";
|
|
@@ -9591,7 +9932,7 @@ function applySemanticPageGrouping(sourceTree) {
|
|
|
9591
9932
|
if (node.kind === "document" || node.kind === "page_group") return node;
|
|
9592
9933
|
let nextNode = node;
|
|
9593
9934
|
if (node.kind === "page" && /^page\s+\d+$/i.test(node.title)) {
|
|
9594
|
-
const title =
|
|
9935
|
+
const title = pageHeadingTitleFromText([node.textExcerpt, node.description].filter(Boolean).join(" "), node.title);
|
|
9595
9936
|
if (title !== node.title) {
|
|
9596
9937
|
nextNode = {
|
|
9597
9938
|
...node,
|
|
@@ -9969,8 +10310,8 @@ function applyTitleSectionHierarchy(sourceTree) {
|
|
|
9969
10310
|
const current = updates.get(child.id) ?? child;
|
|
9970
10311
|
const heading = sectionHeadingTitle(current, container);
|
|
9971
10312
|
if (heading) {
|
|
9972
|
-
const
|
|
9973
|
-
const hasOwnContent =
|
|
10313
|
+
const descendants2 = byParent.get(child.id) ?? [];
|
|
10314
|
+
const hasOwnContent = descendants2.some((descendant) => descendant.kind !== "table_row" && descendant.kind !== "table_cell");
|
|
9974
10315
|
let hasFollowingContent = false;
|
|
9975
10316
|
for (const nextChild of directPageChildren.slice(index + 1)) {
|
|
9976
10317
|
const next = updates.get(nextChild.id) ?? nextChild;
|
|
@@ -9988,7 +10329,7 @@ function applyTitleSectionHierarchy(sourceTree) {
|
|
|
9988
10329
|
parentId: container.id,
|
|
9989
10330
|
kind: sectionKindForTitle(heading),
|
|
9990
10331
|
title: heading,
|
|
9991
|
-
description: descriptionWithPages(cleanText([heading, "section"].join(" "), heading), [current, ...
|
|
10332
|
+
description: descriptionWithPages(cleanText([heading, "section"].join(" "), heading), [current, ...descendants2]),
|
|
9992
10333
|
metadata: {
|
|
9993
10334
|
...current.metadata,
|
|
9994
10335
|
organizer: "title_section",
|
|
@@ -10318,13 +10659,16 @@ function buildOperationalProfilePrompt(sourceTree, fallback) {
|
|
|
10318
10659
|
|
|
10319
10660
|
Return only high-value operational facts needed for policy lists, Q&A, compliance, and certificate generation:
|
|
10320
10661
|
- policy number, named insured, insurer/carrier/security, broker/producer, policy period, retroactive date, premium
|
|
10321
|
-
- coverage
|
|
10662
|
+
- coverage units with their own nested limit terms, deductibles/retentions, retroactive dates, premiums, and form references
|
|
10322
10663
|
- coverage type labels
|
|
10323
10664
|
|
|
10324
10665
|
Rules:
|
|
10325
10666
|
- Every returned value must include sourceNodeIds or sourceSpanIds from the provided nodes.
|
|
10326
10667
|
- If a value is not directly supported, omit it.
|
|
10327
10668
|
- Prefer declarations, schedules, premium tables, and endorsement schedules over generic policy wording.
|
|
10669
|
+
- Treat an endorsement as one coverage unit when it contains a schedule. Do not split an endorsement schedule into generic rows like "Aggregate Limit".
|
|
10670
|
+
- For coverage schedules, put each claim, aggregate, sublimit, retention, deductible, and retroactive date values in coverages[].limits with labels and source IDs. Keep the legacy coverages[].limit as the primary display value only.
|
|
10671
|
+
- Use coverageOrigin: "endorsement" for endorsement units and "core" for declarations/core policy coverage units.
|
|
10328
10672
|
- Do not copy entire policy wording into fields.
|
|
10329
10673
|
|
|
10330
10674
|
Deterministic baseline:
|
|
@@ -10440,11 +10784,18 @@ function materializeDocument(params) {
|
|
|
10440
10784
|
limit: coverage.limit,
|
|
10441
10785
|
deductible: coverage.deductible,
|
|
10442
10786
|
premium: coverage.premium,
|
|
10787
|
+
retroactiveDate: coverage.retroactiveDate,
|
|
10443
10788
|
formNumber: coverage.formNumber,
|
|
10444
10789
|
sectionRef: coverage.sectionRef,
|
|
10790
|
+
coverageOrigin: coverage.coverageOrigin,
|
|
10791
|
+
endorsementNumber: coverage.endorsementNumber,
|
|
10792
|
+
limits: coverage.limits,
|
|
10445
10793
|
sourceSpanIds: coverage.sourceSpanIds,
|
|
10446
10794
|
documentNodeId: coverage.sourceNodeIds[0],
|
|
10447
|
-
originalContent: [
|
|
10795
|
+
originalContent: [
|
|
10796
|
+
coverage.name,
|
|
10797
|
+
...coverage.limits?.length ? coverage.limits.map((term) => `${term.label}: ${term.value}`) : [coverage.limit, coverage.deductible, coverage.premium]
|
|
10798
|
+
].filter(Boolean).join(" | ")
|
|
10448
10799
|
}));
|
|
10449
10800
|
const documentOutline = sourceTreeToOutline(params.sourceTree);
|
|
10450
10801
|
const documentMetadata = {
|
|
@@ -15570,6 +15921,7 @@ export {
|
|
|
15570
15921
|
MissingInfoQuestionSchema,
|
|
15571
15922
|
NamedInsuredSchema,
|
|
15572
15923
|
OperationalCoverageLineSchema,
|
|
15924
|
+
OperationalCoverageTermSchema,
|
|
15573
15925
|
OperationalEndorsementSupportSchema,
|
|
15574
15926
|
OperationalPartySchema,
|
|
15575
15927
|
PERSONAL_AUTO_USAGES,
|