@claritylabs/cl-sdk 0.16.1 → 0.17.0
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 +526 -15
- package/dist/index.d.ts +526 -15
- package/dist/index.js +823 -263
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +821 -263
- package/dist/index.mjs.map +1 -1
- package/dist/storage-sqlite.d.mts +223 -1
- package/dist/storage-sqlite.d.ts +223 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1226,6 +1226,29 @@ var AuxiliaryFactSchema = z16.object({
|
|
|
1226
1226
|
subject: z16.string().optional(),
|
|
1227
1227
|
context: z16.string().optional()
|
|
1228
1228
|
});
|
|
1229
|
+
var DefinitionSchema = z16.object({
|
|
1230
|
+
term: z16.string(),
|
|
1231
|
+
definition: z16.string(),
|
|
1232
|
+
pageNumber: z16.number().optional(),
|
|
1233
|
+
formNumber: z16.string().optional(),
|
|
1234
|
+
formTitle: z16.string().optional(),
|
|
1235
|
+
sectionRef: z16.string().optional(),
|
|
1236
|
+
originalContent: z16.string().optional()
|
|
1237
|
+
});
|
|
1238
|
+
var CoveredReasonSchema = z16.object({
|
|
1239
|
+
coverageName: z16.string(),
|
|
1240
|
+
reasonNumber: z16.string().optional(),
|
|
1241
|
+
title: z16.string().optional(),
|
|
1242
|
+
content: z16.string(),
|
|
1243
|
+
conditions: z16.array(z16.string()).optional(),
|
|
1244
|
+
exceptions: z16.array(z16.string()).optional(),
|
|
1245
|
+
appliesTo: z16.array(z16.string()).optional(),
|
|
1246
|
+
pageNumber: z16.number().optional(),
|
|
1247
|
+
formNumber: z16.string().optional(),
|
|
1248
|
+
formTitle: z16.string().optional(),
|
|
1249
|
+
sectionRef: z16.string().optional(),
|
|
1250
|
+
originalContent: z16.string().optional()
|
|
1251
|
+
});
|
|
1229
1252
|
var BaseDocumentFields = {
|
|
1230
1253
|
id: z16.string(),
|
|
1231
1254
|
carrier: z16.string(),
|
|
@@ -1236,6 +1259,8 @@ var BaseDocumentFields = {
|
|
|
1236
1259
|
policyTypes: z16.array(z16.string()).optional(),
|
|
1237
1260
|
coverages: z16.array(CoverageSchema),
|
|
1238
1261
|
sections: z16.array(SectionSchema).optional(),
|
|
1262
|
+
definitions: z16.array(DefinitionSchema).optional(),
|
|
1263
|
+
coveredReasons: z16.array(CoveredReasonSchema).optional(),
|
|
1239
1264
|
// Enriched fields (v1.2+)
|
|
1240
1265
|
carrierLegalName: z16.string().optional(),
|
|
1241
1266
|
carrierNaicNumber: z16.string().optional(),
|
|
@@ -1689,13 +1714,26 @@ function getDeclarationFields(doc) {
|
|
|
1689
1714
|
return Array.isArray(decl?.fields) ? decl.fields : [];
|
|
1690
1715
|
}
|
|
1691
1716
|
function fieldMatches(fieldName, patterns) {
|
|
1692
|
-
const lower = fieldName
|
|
1693
|
-
return patterns.some((p) => lower === p
|
|
1717
|
+
const lower = normalizeFieldName(fieldName);
|
|
1718
|
+
return patterns.some((p) => lower === normalizeFieldName(p));
|
|
1719
|
+
}
|
|
1720
|
+
function normalizeFieldName(fieldName) {
|
|
1721
|
+
return fieldName.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1694
1722
|
}
|
|
1695
|
-
function findFieldValue(fields, patterns) {
|
|
1696
|
-
const match = fields.find((f) => fieldMatches(f.field, patterns));
|
|
1723
|
+
function findFieldValue(fields, patterns, reject) {
|
|
1724
|
+
const match = fields.find((f) => fieldMatches(f.field, patterns) && !reject?.(f));
|
|
1697
1725
|
return match?.value;
|
|
1698
1726
|
}
|
|
1727
|
+
function stringValue(value) {
|
|
1728
|
+
return typeof value === "string" && value.trim() ? value : void 0;
|
|
1729
|
+
}
|
|
1730
|
+
function findRawString(raw, keys) {
|
|
1731
|
+
for (const key of keys) {
|
|
1732
|
+
const value = stringValue(raw[key]);
|
|
1733
|
+
if (value) return value;
|
|
1734
|
+
}
|
|
1735
|
+
return void 0;
|
|
1736
|
+
}
|
|
1699
1737
|
function promoteCarrierFields(doc) {
|
|
1700
1738
|
const raw = doc;
|
|
1701
1739
|
if (!raw.carrierNaicNumber && raw.naicNumber) {
|
|
@@ -2011,8 +2049,126 @@ function synthesizeDeductibles(doc) {
|
|
|
2011
2049
|
raw.deductibles = deductibles;
|
|
2012
2050
|
}
|
|
2013
2051
|
}
|
|
2014
|
-
var PREMIUM_PATTERNS = [
|
|
2015
|
-
|
|
2052
|
+
var PREMIUM_PATTERNS = [
|
|
2053
|
+
"premium",
|
|
2054
|
+
"premiumAmount",
|
|
2055
|
+
"premium amount",
|
|
2056
|
+
"totalPremium",
|
|
2057
|
+
"total premium",
|
|
2058
|
+
"totalPolicyPremium",
|
|
2059
|
+
"total policy premium",
|
|
2060
|
+
"annualPremium",
|
|
2061
|
+
"annual premium",
|
|
2062
|
+
"estimatedAnnualPremium",
|
|
2063
|
+
"estimated annual premium",
|
|
2064
|
+
"policyPremium",
|
|
2065
|
+
"policy premium",
|
|
2066
|
+
"basePremium",
|
|
2067
|
+
"base premium",
|
|
2068
|
+
"planCost",
|
|
2069
|
+
"plan cost",
|
|
2070
|
+
"policyCost",
|
|
2071
|
+
"policy cost",
|
|
2072
|
+
"premiumSubtotal",
|
|
2073
|
+
"premium subtotal",
|
|
2074
|
+
"subtotalPremium",
|
|
2075
|
+
"subtotal premium",
|
|
2076
|
+
"quotedPremium",
|
|
2077
|
+
"quoted premium"
|
|
2078
|
+
];
|
|
2079
|
+
var TOTAL_COST_PATTERNS = [
|
|
2080
|
+
"totalCost",
|
|
2081
|
+
"total cost",
|
|
2082
|
+
"total",
|
|
2083
|
+
"totalDue",
|
|
2084
|
+
"total due",
|
|
2085
|
+
"amountPaid",
|
|
2086
|
+
"amount paid",
|
|
2087
|
+
"totalPaid",
|
|
2088
|
+
"total paid",
|
|
2089
|
+
"totalPrice",
|
|
2090
|
+
"total price",
|
|
2091
|
+
"totalTripCost",
|
|
2092
|
+
"total trip cost",
|
|
2093
|
+
"amountCharged",
|
|
2094
|
+
"amount charged",
|
|
2095
|
+
"amountDue",
|
|
2096
|
+
"amount due",
|
|
2097
|
+
"totalAmountDue",
|
|
2098
|
+
"total amount due",
|
|
2099
|
+
"totalAmount",
|
|
2100
|
+
"total amount",
|
|
2101
|
+
"grandTotal",
|
|
2102
|
+
"grand total",
|
|
2103
|
+
"totalPayable",
|
|
2104
|
+
"total payable",
|
|
2105
|
+
"totalCharges",
|
|
2106
|
+
"total charges",
|
|
2107
|
+
"totalPolicyCost",
|
|
2108
|
+
"total policy cost"
|
|
2109
|
+
];
|
|
2110
|
+
var PREMIUM_RAW_KEYS = [
|
|
2111
|
+
"premium",
|
|
2112
|
+
"premiumAmount",
|
|
2113
|
+
"premium_amount",
|
|
2114
|
+
"totalPremium",
|
|
2115
|
+
"totalPolicyPremium",
|
|
2116
|
+
"annualPremium",
|
|
2117
|
+
"estimatedAnnualPremium",
|
|
2118
|
+
"policyPremium",
|
|
2119
|
+
"basePremium",
|
|
2120
|
+
"planCost",
|
|
2121
|
+
"policyCost",
|
|
2122
|
+
"premiumSubtotal",
|
|
2123
|
+
"subtotalPremium",
|
|
2124
|
+
"quotedPremium"
|
|
2125
|
+
];
|
|
2126
|
+
var TOTAL_COST_RAW_KEYS = [
|
|
2127
|
+
"totalCost",
|
|
2128
|
+
"total_cost",
|
|
2129
|
+
"total",
|
|
2130
|
+
"totalDue",
|
|
2131
|
+
"amountPaid",
|
|
2132
|
+
"amount_paid",
|
|
2133
|
+
"totalPaid",
|
|
2134
|
+
"total_paid",
|
|
2135
|
+
"totalPrice",
|
|
2136
|
+
"totalTripCost",
|
|
2137
|
+
"amountCharged",
|
|
2138
|
+
"amountDue",
|
|
2139
|
+
"totalAmountDue",
|
|
2140
|
+
"totalAmount",
|
|
2141
|
+
"grandTotal",
|
|
2142
|
+
"totalPayable",
|
|
2143
|
+
"totalCharges",
|
|
2144
|
+
"totalPolicyCost"
|
|
2145
|
+
];
|
|
2146
|
+
function isTaxOrFeeField(fieldName) {
|
|
2147
|
+
const normalized = normalizeFieldName(fieldName);
|
|
2148
|
+
return /tax|gst|hst|pst|qst|fee|surcharge|assessment|stamp|filing|inspection/.test(normalized);
|
|
2149
|
+
}
|
|
2150
|
+
function isTotalCostField(fieldName) {
|
|
2151
|
+
return fieldMatches(fieldName, TOTAL_COST_PATTERNS);
|
|
2152
|
+
}
|
|
2153
|
+
function taxFeeType(fieldName) {
|
|
2154
|
+
const normalized = normalizeFieldName(fieldName);
|
|
2155
|
+
if (normalized.includes("tax") || ["gst", "hst", "pst", "qst"].some((token) => normalized.includes(token))) return "tax";
|
|
2156
|
+
if (normalized.includes("surcharge")) return "surcharge";
|
|
2157
|
+
if (normalized.includes("assessment")) return "assessment";
|
|
2158
|
+
if (normalized.includes("fee") || normalized.includes("stamp") || normalized.includes("filing")) return "fee";
|
|
2159
|
+
return void 0;
|
|
2160
|
+
}
|
|
2161
|
+
function titleizeFieldName(fieldName) {
|
|
2162
|
+
const spaced = fieldName.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim();
|
|
2163
|
+
return spaced.replace(/\b\w/g, (letter) => letter.toUpperCase());
|
|
2164
|
+
}
|
|
2165
|
+
function taxFeeKey(item) {
|
|
2166
|
+
return [
|
|
2167
|
+
normalizeFieldName(item.name),
|
|
2168
|
+
normalizeFieldName(item.amount),
|
|
2169
|
+
item.type ?? ""
|
|
2170
|
+
].join("|");
|
|
2171
|
+
}
|
|
2016
2172
|
function absorbNegative(value) {
|
|
2017
2173
|
return value.replace(/^-\s*/, "").replace(/^\(\s*(.*?)\s*\)$/, "$1");
|
|
2018
2174
|
}
|
|
@@ -2020,16 +2176,41 @@ function promotePremium(doc) {
|
|
|
2020
2176
|
const raw = doc;
|
|
2021
2177
|
const fields = getDeclarationFields(doc);
|
|
2022
2178
|
if (!raw.premium) {
|
|
2023
|
-
const premium = findFieldValue(fields, PREMIUM_PATTERNS);
|
|
2179
|
+
const premium = findRawString(raw, PREMIUM_RAW_KEYS) ?? findFieldValue(fields, PREMIUM_PATTERNS, (field) => isTaxOrFeeField(field.field));
|
|
2024
2180
|
if (premium) raw.premium = premium;
|
|
2025
2181
|
}
|
|
2026
2182
|
if (!raw.totalCost) {
|
|
2027
|
-
const totalCost = findFieldValue(fields, TOTAL_COST_PATTERNS);
|
|
2183
|
+
const totalCost = findRawString(raw, TOTAL_COST_RAW_KEYS) ?? findFieldValue(fields, TOTAL_COST_PATTERNS);
|
|
2028
2184
|
if (totalCost) raw.totalCost = totalCost;
|
|
2029
2185
|
}
|
|
2030
2186
|
if (typeof raw.premium === "string") raw.premium = absorbNegative(raw.premium);
|
|
2031
2187
|
if (typeof raw.totalCost === "string") raw.totalCost = absorbNegative(raw.totalCost);
|
|
2032
2188
|
}
|
|
2189
|
+
function synthesizeTaxesAndFees(doc) {
|
|
2190
|
+
const raw = doc;
|
|
2191
|
+
const fields = getDeclarationFields(doc);
|
|
2192
|
+
if (fields.length === 0) return;
|
|
2193
|
+
const existing = Array.isArray(raw.taxesAndFees) ? raw.taxesAndFees : [];
|
|
2194
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
2195
|
+
for (const item of existing) {
|
|
2196
|
+
if (!item?.name || !item?.amount) continue;
|
|
2197
|
+
byKey.set(taxFeeKey(item), item);
|
|
2198
|
+
}
|
|
2199
|
+
for (const field of fields) {
|
|
2200
|
+
if (!field.value?.trim()) continue;
|
|
2201
|
+
if (!isTaxOrFeeField(field.field)) continue;
|
|
2202
|
+
if (isTotalCostField(field.field)) continue;
|
|
2203
|
+
const item = {
|
|
2204
|
+
name: titleizeFieldName(field.field),
|
|
2205
|
+
amount: absorbNegative(field.value),
|
|
2206
|
+
...taxFeeType(field.field) ? { type: taxFeeType(field.field) } : {}
|
|
2207
|
+
};
|
|
2208
|
+
byKey.set(taxFeeKey(item), item);
|
|
2209
|
+
}
|
|
2210
|
+
if (byKey.size > 0) {
|
|
2211
|
+
raw.taxesAndFees = [...byKey.values()];
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2033
2214
|
function promoteExtractedFields(doc) {
|
|
2034
2215
|
promoteCarrierFields(doc);
|
|
2035
2216
|
promoteBroker(doc);
|
|
@@ -2037,6 +2218,7 @@ function promoteExtractedFields(doc) {
|
|
|
2037
2218
|
promoteLocations(doc);
|
|
2038
2219
|
synthesizeLimits(doc);
|
|
2039
2220
|
synthesizeDeductibles(doc);
|
|
2221
|
+
synthesizeTaxesAndFees(doc);
|
|
2040
2222
|
promotePremium(doc);
|
|
2041
2223
|
}
|
|
2042
2224
|
|
|
@@ -2054,6 +2236,8 @@ function assembleDocument(documentId, documentType, memory) {
|
|
|
2054
2236
|
const sections = memory.get("sections");
|
|
2055
2237
|
const supplementary = memory.get("supplementary");
|
|
2056
2238
|
const formInventory = memory.get("form_inventory");
|
|
2239
|
+
const definitions = memory.get("definitions");
|
|
2240
|
+
const coveredReasons = memory.get("covered_reasons");
|
|
2057
2241
|
const classify = memory.get("classify");
|
|
2058
2242
|
const base = {
|
|
2059
2243
|
id: documentId,
|
|
@@ -2075,6 +2259,8 @@ function assembleDocument(documentId, documentType, memory) {
|
|
|
2075
2259
|
conditions: conditions?.conditions,
|
|
2076
2260
|
sections: sections?.sections,
|
|
2077
2261
|
formInventory: formInventory?.forms,
|
|
2262
|
+
definitions: definitions?.definitions,
|
|
2263
|
+
coveredReasons: coveredReasons?.coveredReasons ?? coveredReasons?.covered_reasons,
|
|
2078
2264
|
declarations: declarations ? sanitizeNulls(declarations) : void 0,
|
|
2079
2265
|
...sanitizeNulls(lossHistory ?? {})
|
|
2080
2266
|
};
|
|
@@ -2234,6 +2420,21 @@ function collectContentFields(doc) {
|
|
|
2234
2420
|
add(`conditions[${i}].content`, doc.conditions[i].content);
|
|
2235
2421
|
}
|
|
2236
2422
|
}
|
|
2423
|
+
const extendedDoc = doc;
|
|
2424
|
+
if (extendedDoc.definitions) {
|
|
2425
|
+
for (let i = 0; i < extendedDoc.definitions.length; i++) {
|
|
2426
|
+
add(`definitions[${i}].definition`, extendedDoc.definitions[i].definition);
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
const coveredReasons = extendedDoc.coveredReasons ?? extendedDoc.covered_reasons;
|
|
2430
|
+
if (coveredReasons) {
|
|
2431
|
+
for (let i = 0; i < coveredReasons.length; i++) {
|
|
2432
|
+
add(`coveredReasons[${i}].content`, coveredReasons[i].content);
|
|
2433
|
+
coveredReasons[i].conditions?.forEach((condition, j) => {
|
|
2434
|
+
add(`coveredReasons[${i}].conditions[${j}]`, condition);
|
|
2435
|
+
});
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
2237
2438
|
return entries;
|
|
2238
2439
|
}
|
|
2239
2440
|
function parseFormatResponse(response) {
|
|
@@ -2249,6 +2450,10 @@ function parseFormatResponse(response) {
|
|
|
2249
2450
|
return results;
|
|
2250
2451
|
}
|
|
2251
2452
|
function applyFormattedContent(doc, entries, formatted) {
|
|
2453
|
+
const docRecord = doc;
|
|
2454
|
+
if (!docRecord.coveredReasons && docRecord.covered_reasons) {
|
|
2455
|
+
docRecord.coveredReasons = docRecord.covered_reasons;
|
|
2456
|
+
}
|
|
2252
2457
|
for (const entry of entries) {
|
|
2253
2458
|
const cleaned = formatted.get(entry.id);
|
|
2254
2459
|
if (!cleaned) continue;
|
|
@@ -2257,6 +2462,14 @@ function applyFormattedContent(doc, entries, formatted) {
|
|
|
2257
2462
|
const [, field, idx1, sub1, idx2, sub2] = segments;
|
|
2258
2463
|
if (!sub1) {
|
|
2259
2464
|
doc[field] = cleaned;
|
|
2465
|
+
} else if (idx2 && !sub2) {
|
|
2466
|
+
const arr = doc[field];
|
|
2467
|
+
if (arr && arr[Number(idx1)]) {
|
|
2468
|
+
const nested = arr[Number(idx1)][sub1];
|
|
2469
|
+
if (Array.isArray(nested)) {
|
|
2470
|
+
nested[Number(idx2)] = cleaned;
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2260
2473
|
} else if (!sub2) {
|
|
2261
2474
|
const arr = doc[field];
|
|
2262
2475
|
if (arr && arr[Number(idx1)]) {
|
|
@@ -2321,6 +2534,16 @@ function formatAddress(addr) {
|
|
|
2321
2534
|
const parts = [addr.street1, addr.street2, addr.city, addr.state, addr.zip, addr.country].filter(Boolean);
|
|
2322
2535
|
return parts.join(", ");
|
|
2323
2536
|
}
|
|
2537
|
+
function asRecordArray(value) {
|
|
2538
|
+
return Array.isArray(value) ? value.filter((item) => Boolean(item) && typeof item === "object" && !Array.isArray(item)) : [];
|
|
2539
|
+
}
|
|
2540
|
+
function firstString(item, keys) {
|
|
2541
|
+
for (const key of keys) {
|
|
2542
|
+
const value = item[key];
|
|
2543
|
+
if (typeof value === "string" && value.trim()) return value;
|
|
2544
|
+
}
|
|
2545
|
+
return void 0;
|
|
2546
|
+
}
|
|
2324
2547
|
function chunkDocument(doc) {
|
|
2325
2548
|
const ensureArray = (v) => Array.isArray(v) ? v : [];
|
|
2326
2549
|
doc = {
|
|
@@ -2334,6 +2557,7 @@ function chunkDocument(doc) {
|
|
|
2334
2557
|
const chunks = [];
|
|
2335
2558
|
const docId = doc.id;
|
|
2336
2559
|
const policyTypesStr = doc.policyTypes?.length ? doc.policyTypes.join(",") : void 0;
|
|
2560
|
+
const extendedDoc = doc;
|
|
2337
2561
|
function stringMetadata(entries) {
|
|
2338
2562
|
const base = Object.fromEntries(
|
|
2339
2563
|
Object.entries(entries).filter(([, value]) => value !== void 0 && value !== null && String(value).length > 0).map(([key, value]) => [key, String(value)])
|
|
@@ -2691,6 +2915,82 @@ ${exc.content}`.trim(),
|
|
|
2691
2915
|
})
|
|
2692
2916
|
});
|
|
2693
2917
|
});
|
|
2918
|
+
asRecordArray(extendedDoc.definitions).forEach((definition, i) => {
|
|
2919
|
+
const term = firstString(definition, ["term", "name", "title"]) ?? `Definition ${i + 1}`;
|
|
2920
|
+
const body = firstString(definition, ["definition", "content", "text", "meaning"]);
|
|
2921
|
+
chunks.push({
|
|
2922
|
+
id: `${docId}:definition:${i}`,
|
|
2923
|
+
documentId: docId,
|
|
2924
|
+
type: "definition",
|
|
2925
|
+
text: [
|
|
2926
|
+
`Definition: ${term}`,
|
|
2927
|
+
body,
|
|
2928
|
+
firstString(definition, ["originalContent", "source"]) ? `Source: ${firstString(definition, ["originalContent", "source"])}` : null
|
|
2929
|
+
].filter(Boolean).join("\n"),
|
|
2930
|
+
metadata: stringMetadata({
|
|
2931
|
+
term,
|
|
2932
|
+
formNumber: firstString(definition, ["formNumber"]),
|
|
2933
|
+
formTitle: firstString(definition, ["formTitle"]),
|
|
2934
|
+
pageNumber: typeof definition.pageNumber === "number" ? definition.pageNumber : void 0,
|
|
2935
|
+
sectionRef: firstString(definition, ["sectionRef", "sectionTitle"]),
|
|
2936
|
+
documentType: doc.type
|
|
2937
|
+
})
|
|
2938
|
+
});
|
|
2939
|
+
});
|
|
2940
|
+
const coveredReasons = asRecordArray(extendedDoc.coveredReasons ?? extendedDoc.covered_reasons);
|
|
2941
|
+
coveredReasons.forEach((coveredReason, i) => {
|
|
2942
|
+
const title = firstString(coveredReason, ["title", "name", "reason", "peril", "cause"]) ?? `Covered Reason ${i + 1}`;
|
|
2943
|
+
const coverageName = firstString(coveredReason, ["coverageName", "coverage", "coveragePart"]);
|
|
2944
|
+
const reasonNumber = firstString(coveredReason, ["reasonNumber", "number"]);
|
|
2945
|
+
const body = firstString(coveredReason, ["content", "description", "text", "coverageGrant"]);
|
|
2946
|
+
chunks.push({
|
|
2947
|
+
id: `${docId}:covered_reason:${i}`,
|
|
2948
|
+
documentId: docId,
|
|
2949
|
+
type: "covered_reason",
|
|
2950
|
+
text: [
|
|
2951
|
+
coverageName ? `Coverage: ${coverageName}` : null,
|
|
2952
|
+
reasonNumber ? `Reason Number: ${reasonNumber}` : null,
|
|
2953
|
+
`Covered Reason: ${title}`,
|
|
2954
|
+
body,
|
|
2955
|
+
firstString(coveredReason, ["originalContent", "source"]) ? `Source: ${firstString(coveredReason, ["originalContent", "source"])}` : null
|
|
2956
|
+
].filter(Boolean).join("\n"),
|
|
2957
|
+
metadata: stringMetadata({
|
|
2958
|
+
coverageName,
|
|
2959
|
+
reasonNumber,
|
|
2960
|
+
title,
|
|
2961
|
+
formNumber: firstString(coveredReason, ["formNumber"]),
|
|
2962
|
+
formTitle: firstString(coveredReason, ["formTitle"]),
|
|
2963
|
+
pageNumber: typeof coveredReason.pageNumber === "number" ? coveredReason.pageNumber : void 0,
|
|
2964
|
+
sectionRef: firstString(coveredReason, ["sectionRef", "sectionTitle"]),
|
|
2965
|
+
documentType: doc.type
|
|
2966
|
+
})
|
|
2967
|
+
});
|
|
2968
|
+
const conditions = Array.isArray(coveredReason.conditions) ? coveredReason.conditions.filter((condition) => typeof condition === "string" && condition.trim().length > 0) : [];
|
|
2969
|
+
conditions.forEach((condition, conditionIndex) => {
|
|
2970
|
+
chunks.push({
|
|
2971
|
+
id: `${docId}:covered_reason:${i}:condition:${conditionIndex}`,
|
|
2972
|
+
documentId: docId,
|
|
2973
|
+
type: "covered_reason",
|
|
2974
|
+
text: [
|
|
2975
|
+
coverageName ? `Coverage: ${coverageName}` : null,
|
|
2976
|
+
reasonNumber ? `Reason Number: ${reasonNumber}` : null,
|
|
2977
|
+
`Covered Reason Condition: ${title}`,
|
|
2978
|
+
condition
|
|
2979
|
+
].filter(Boolean).join("\n"),
|
|
2980
|
+
metadata: stringMetadata({
|
|
2981
|
+
coverageName,
|
|
2982
|
+
reasonNumber,
|
|
2983
|
+
title,
|
|
2984
|
+
conditionIndex,
|
|
2985
|
+
formNumber: firstString(coveredReason, ["formNumber"]),
|
|
2986
|
+
formTitle: firstString(coveredReason, ["formTitle"]),
|
|
2987
|
+
pageNumber: typeof coveredReason.pageNumber === "number" ? coveredReason.pageNumber : void 0,
|
|
2988
|
+
sectionRef: firstString(coveredReason, ["sectionRef", "sectionTitle"]),
|
|
2989
|
+
documentType: doc.type
|
|
2990
|
+
})
|
|
2991
|
+
});
|
|
2992
|
+
});
|
|
2993
|
+
});
|
|
2694
2994
|
if (doc.declarations) {
|
|
2695
2995
|
const decl = doc.declarations;
|
|
2696
2996
|
const declLines = [];
|
|
@@ -3236,6 +3536,13 @@ function dedupeByKey(items, keyFn) {
|
|
|
3236
3536
|
}
|
|
3237
3537
|
return merged;
|
|
3238
3538
|
}
|
|
3539
|
+
function normalizeKeyPart(value) {
|
|
3540
|
+
if (value === void 0 || value === null) return "";
|
|
3541
|
+
return String(value).toLowerCase().replace(/&/g, "and").replace(/[^a-z0-9]+/g, "");
|
|
3542
|
+
}
|
|
3543
|
+
function keyFromParts(...parts) {
|
|
3544
|
+
return parts.map(normalizeKeyPart).join("|");
|
|
3545
|
+
}
|
|
3239
3546
|
function mergeUniqueObjects(existing, incoming, keyFn) {
|
|
3240
3547
|
return dedupeByKey([...existing, ...incoming], keyFn);
|
|
3241
3548
|
}
|
|
@@ -3264,13 +3571,13 @@ function mergeCoverageLimits(existing, incoming) {
|
|
|
3264
3571
|
const merged = mergeShallowPreferPresent(existing, incoming);
|
|
3265
3572
|
const existingCoverages = Array.isArray(existing.coverages) ? existing.coverages : [];
|
|
3266
3573
|
const incomingCoverages = Array.isArray(incoming.coverages) ? incoming.coverages : [];
|
|
3267
|
-
const coverageKey = (coverage) =>
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3574
|
+
const coverageKey = (coverage) => keyFromParts(
|
|
3575
|
+
coverage.name,
|
|
3576
|
+
coverage.limitType,
|
|
3577
|
+
coverage.limit,
|
|
3578
|
+
coverage.deductible,
|
|
3579
|
+
coverage.formNumber
|
|
3580
|
+
);
|
|
3274
3581
|
const byKey = /* @__PURE__ */ new Map();
|
|
3275
3582
|
for (const coverage of [...existingCoverages, ...incomingCoverages]) {
|
|
3276
3583
|
const key = coverageKey(coverage);
|
|
@@ -3284,11 +3591,11 @@ function mergeDeclarations(existing, incoming) {
|
|
|
3284
3591
|
const merged = mergeShallowPreferPresent(existing, incoming);
|
|
3285
3592
|
const existingFields = Array.isArray(existing.fields) ? existing.fields : [];
|
|
3286
3593
|
const incomingFields = Array.isArray(incoming.fields) ? incoming.fields : [];
|
|
3287
|
-
merged.fields = mergeUniqueObjects(existingFields, incomingFields, (field) =>
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3594
|
+
merged.fields = mergeUniqueObjects(existingFields, incomingFields, (field) => keyFromParts(
|
|
3595
|
+
field.field,
|
|
3596
|
+
field.value,
|
|
3597
|
+
field.section
|
|
3598
|
+
));
|
|
3292
3599
|
return merged;
|
|
3293
3600
|
}
|
|
3294
3601
|
function mergeArrayPayload(existing, incoming, arrayKey, keyFn) {
|
|
@@ -3298,30 +3605,53 @@ function mergeArrayPayload(existing, incoming, arrayKey, keyFn) {
|
|
|
3298
3605
|
merged[arrayKey] = mergeUniqueObjects(existingItems, incomingItems, keyFn);
|
|
3299
3606
|
return merged;
|
|
3300
3607
|
}
|
|
3608
|
+
function readArray(record, ...keys) {
|
|
3609
|
+
for (const key of keys) {
|
|
3610
|
+
if (Array.isArray(record[key])) return record[key];
|
|
3611
|
+
}
|
|
3612
|
+
return [];
|
|
3613
|
+
}
|
|
3614
|
+
function mergeAliasedArrayPayload(existing, incoming, outputKey, inputKeys, keyFn) {
|
|
3615
|
+
const merged = mergeShallowPreferPresent(existing, incoming);
|
|
3616
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
3617
|
+
for (const item of [
|
|
3618
|
+
...readArray(existing, outputKey, ...inputKeys),
|
|
3619
|
+
...readArray(incoming, outputKey, ...inputKeys)
|
|
3620
|
+
]) {
|
|
3621
|
+
const key = keyFn(item);
|
|
3622
|
+
const current = byKey.get(key);
|
|
3623
|
+
byKey.set(key, current ? mergeShallowPreferPresent(current, item) : item);
|
|
3624
|
+
}
|
|
3625
|
+
merged[outputKey] = [...byKey.values()];
|
|
3626
|
+
for (const key of inputKeys) {
|
|
3627
|
+
if (key !== outputKey) delete merged[key];
|
|
3628
|
+
}
|
|
3629
|
+
return merged;
|
|
3630
|
+
}
|
|
3301
3631
|
function mergeSupplementary(existing, incoming) {
|
|
3302
3632
|
const merged = mergeShallowPreferPresent(existing, incoming);
|
|
3303
3633
|
const mergeContactArray = (arrayKey) => {
|
|
3304
3634
|
const existingItems = Array.isArray(existing[arrayKey]) ? existing[arrayKey] : [];
|
|
3305
3635
|
const incomingItems = Array.isArray(incoming[arrayKey]) ? incoming[arrayKey] : [];
|
|
3306
|
-
merged[arrayKey] = mergeUniqueObjects(existingItems, incomingItems, (item) =>
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3636
|
+
merged[arrayKey] = mergeUniqueObjects(existingItems, incomingItems, (item) => keyFromParts(
|
|
3637
|
+
item.name,
|
|
3638
|
+
item.phone,
|
|
3639
|
+
item.email,
|
|
3640
|
+
item.address,
|
|
3641
|
+
item.type
|
|
3642
|
+
));
|
|
3313
3643
|
};
|
|
3314
3644
|
mergeContactArray("regulatoryContacts");
|
|
3315
3645
|
mergeContactArray("claimsContacts");
|
|
3316
3646
|
mergeContactArray("thirdPartyAdministrators");
|
|
3317
3647
|
const existingFacts = Array.isArray(existing.auxiliaryFacts) ? existing.auxiliaryFacts : [];
|
|
3318
3648
|
const incomingFacts = Array.isArray(incoming.auxiliaryFacts) ? incoming.auxiliaryFacts : [];
|
|
3319
|
-
merged.auxiliaryFacts = mergeUniqueObjects(existingFacts, incomingFacts, (item) =>
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3649
|
+
merged.auxiliaryFacts = mergeUniqueObjects(existingFacts, incomingFacts, (item) => keyFromParts(
|
|
3650
|
+
item.key,
|
|
3651
|
+
item.value,
|
|
3652
|
+
item.subject,
|
|
3653
|
+
item.context
|
|
3654
|
+
));
|
|
3325
3655
|
return merged;
|
|
3326
3656
|
}
|
|
3327
3657
|
function mergeExtractorResult(extractorName, existing, incoming) {
|
|
@@ -3342,31 +3672,43 @@ function mergeExtractorResult(extractorName, existing, incoming) {
|
|
|
3342
3672
|
return mergeCoverageLimits(current, next);
|
|
3343
3673
|
case "declarations":
|
|
3344
3674
|
return mergeDeclarations(current, next);
|
|
3675
|
+
case "definitions":
|
|
3676
|
+
return mergeArrayPayload(current, next, "definitions", (item) => keyFromParts(
|
|
3677
|
+
item.term ?? item.name ?? item.key,
|
|
3678
|
+
item.pageNumber ?? item.pageStart
|
|
3679
|
+
));
|
|
3680
|
+
case "covered_reasons":
|
|
3681
|
+
return mergeAliasedArrayPayload(current, next, "coveredReasons", ["covered_reasons"], (item) => keyFromParts(
|
|
3682
|
+
item.coverageName ?? item.coverage,
|
|
3683
|
+
item.reasonNumber ?? item.number,
|
|
3684
|
+
item.title ?? item.reason ?? item.name ?? item.cause,
|
|
3685
|
+
item.pageNumber ?? item.pageStart
|
|
3686
|
+
));
|
|
3345
3687
|
case "endorsements":
|
|
3346
|
-
return mergeArrayPayload(current, next, "endorsements", (item) =>
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3688
|
+
return mergeArrayPayload(current, next, "endorsements", (item) => keyFromParts(
|
|
3689
|
+
item.formNumber,
|
|
3690
|
+
item.title,
|
|
3691
|
+
item.pageStart
|
|
3692
|
+
));
|
|
3351
3693
|
case "exclusions":
|
|
3352
|
-
return mergeArrayPayload(current, next, "exclusions", (item) =>
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3694
|
+
return mergeArrayPayload(current, next, "exclusions", (item) => keyFromParts(
|
|
3695
|
+
item.name,
|
|
3696
|
+
item.formNumber,
|
|
3697
|
+
item.pageNumber
|
|
3698
|
+
));
|
|
3357
3699
|
case "conditions":
|
|
3358
|
-
return mergeArrayPayload(current, next, "conditions", (item) =>
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3700
|
+
return mergeArrayPayload(current, next, "conditions", (item) => keyFromParts(
|
|
3701
|
+
item.name,
|
|
3702
|
+
item.conditionType,
|
|
3703
|
+
item.pageNumber
|
|
3704
|
+
));
|
|
3363
3705
|
case "sections":
|
|
3364
|
-
return mergeArrayPayload(current, next, "sections", (item) =>
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3706
|
+
return mergeArrayPayload(current, next, "sections", (item) => keyFromParts(
|
|
3707
|
+
item.title,
|
|
3708
|
+
item.type,
|
|
3709
|
+
item.pageStart,
|
|
3710
|
+
item.pageEnd
|
|
3711
|
+
));
|
|
3370
3712
|
default:
|
|
3371
3713
|
return mergeShallowPreferPresent(current, next);
|
|
3372
3714
|
}
|
|
@@ -4225,6 +4567,8 @@ var PageExtractorSchema = z20.enum([
|
|
|
4225
4567
|
"carrier_info",
|
|
4226
4568
|
"named_insured",
|
|
4227
4569
|
"coverage_limits",
|
|
4570
|
+
"covered_reasons",
|
|
4571
|
+
"definitions",
|
|
4228
4572
|
"endorsements",
|
|
4229
4573
|
"exclusions",
|
|
4230
4574
|
"conditions",
|
|
@@ -4271,6 +4615,8 @@ Available extractors:
|
|
|
4271
4615
|
- carrier_info
|
|
4272
4616
|
- named_insured
|
|
4273
4617
|
- coverage_limits
|
|
4618
|
+
- covered_reasons
|
|
4619
|
+
- definitions
|
|
4274
4620
|
- endorsements
|
|
4275
4621
|
- exclusions
|
|
4276
4622
|
- conditions
|
|
@@ -4284,6 +4630,8 @@ Rules:
|
|
|
4284
4630
|
- Identify the broad section or form context first, then assign focused extractors within that context.
|
|
4285
4631
|
- Use specific extractors for declarations, schedules, endorsements, exclusions, conditions, premium pages, and loss runs.
|
|
4286
4632
|
- Use "sections" for pages that contain substantive policy text or mixed content that should still be preserved as raw sections.
|
|
4633
|
+
- Use "definitions" for policy-form pages containing defined terms, definitions sections, or term meaning clauses.
|
|
4634
|
+
- Use "covered_reasons" for pages listing covered causes of loss, covered reasons, covered perils, named perils, covered events, or covered loss triggers.
|
|
4287
4635
|
- Avoid assigning broad ranges mentally; decide page by page.
|
|
4288
4636
|
- A page may map to multiple extractors if it legitimately contains multiple relevant sections.
|
|
4289
4637
|
- Prefer declarations and schedules for numeric limits/deductibles over later generic form wording.
|
|
@@ -4291,6 +4639,7 @@ Rules:
|
|
|
4291
4639
|
- Do NOT assign "coverage_limits" for generic policy-form or endorsement text that merely explains how limits, deductibles, waiting periods, or coinsurance work, or that says values are "shown in the declarations", "shown in the schedule", "as stated", or "if applicable".
|
|
4292
4640
|
- Headings like "Limits of Insurance", "Deductible", "Coinsurance", "Loss Conditions", or "Definitions" inside a policy form usually indicate form language, not declarations or schedules.
|
|
4293
4641
|
- Continuation pages near the end of a form should stay mapped to "sections" plus "conditions"/"exclusions" when applicable, even if they mention limits or deductibles.
|
|
4642
|
+
- Covered causes/reasons and definitions often span a whole form section; tag every substantive page in that section, not just the heading page.
|
|
4294
4643
|
- When a form inventory entry identifies a page range as a specific form type (e.g., endorsement, coverage, application), use that classification to guide your extractor choice. Do not assign "coverage_limits" to pages the inventory identifies as endorsement or condition/exclusion forms unless the page contains actual schedule values.
|
|
4295
4644
|
- Do not tag a page with "exclusions" or "conditions" if it only contains a table of contents, page-number reference, running header/footer, or a heading that points to another page without substantive wording.
|
|
4296
4645
|
- If a page appears to be part of a larger exclusion, conditions, or endorsement section within the same form, keep the assignment consistent across nearby pages in that section rather than isolating a single page fragment.
|
|
@@ -4359,9 +4708,13 @@ Mark the extraction as NOT complete if any of these are true:
|
|
|
4359
4708
|
- required fields are missing
|
|
4360
4709
|
- extracted values are generic placeholders like "shown in declarations", "per schedule", "if applicable", "as stated"
|
|
4361
4710
|
- coverage limits or deductibles appear to come from generic form language instead of declaration/schedule-specific values
|
|
4711
|
+
- definitions pages were mapped but no definition records or definition-type sections were extracted
|
|
4712
|
+
- covered causes/reasons pages were mapped but no covered reason, covered peril, covered cause, or matching section records were extracted
|
|
4362
4713
|
- page assignments suggest declaration, schedule, endorsement, exclusion, or condition pages were not actually extracted with the matching focused extractor
|
|
4363
4714
|
- a focused extractor exists but returned too little substance for the relevant pages
|
|
4364
4715
|
|
|
4716
|
+
When reviewing CURRENT EXTRACTION SUMMARY, compare the page-map counts to extracted counts. For definitions and covered_reasons, missing extraction should produce a quality issue and a narrow follow-up task over the mapped page range.
|
|
4717
|
+
|
|
4365
4718
|
Return JSON:
|
|
4366
4719
|
{
|
|
4367
4720
|
"complete": boolean,
|
|
@@ -5005,6 +5358,107 @@ For auxiliaryFacts:
|
|
|
5005
5358
|
Return JSON only.`;
|
|
5006
5359
|
}
|
|
5007
5360
|
|
|
5361
|
+
// src/prompts/extractors/definitions.ts
|
|
5362
|
+
import { z as z34 } from "zod";
|
|
5363
|
+
var DefinitionsSchema = z34.object({
|
|
5364
|
+
definitions: z34.array(
|
|
5365
|
+
z34.object({
|
|
5366
|
+
term: z34.string().describe("Defined term exactly as shown in the document"),
|
|
5367
|
+
definition: z34.string().describe("Full verbatim definition text, preserving original wording"),
|
|
5368
|
+
pageNumber: z34.number().optional().describe("Original document page number"),
|
|
5369
|
+
formNumber: z34.string().optional().describe("Form number where this definition appears"),
|
|
5370
|
+
formTitle: z34.string().optional().describe("Form title where this definition appears"),
|
|
5371
|
+
sectionRef: z34.string().optional().describe("Definition section heading or subsection reference"),
|
|
5372
|
+
originalContent: z34.string().optional().describe("Short verbatim source snippet containing the term and definition")
|
|
5373
|
+
})
|
|
5374
|
+
).describe("All substantive insurance definitions found in the document")
|
|
5375
|
+
});
|
|
5376
|
+
function buildDefinitionsPrompt() {
|
|
5377
|
+
return `You are an expert insurance document analyst. Extract ALL substantive defined terms from this document. Preserve original wording verbatim.
|
|
5378
|
+
|
|
5379
|
+
For EACH definition, extract:
|
|
5380
|
+
- term: defined term exactly as shown \u2014 REQUIRED
|
|
5381
|
+
- definition: full verbatim definition text including all included subparts \u2014 REQUIRED
|
|
5382
|
+
- pageNumber: original document page number where the definition appears
|
|
5383
|
+
- formNumber: form number where the definition appears, if shown
|
|
5384
|
+
- formTitle: form title where the definition appears, if shown
|
|
5385
|
+
- sectionRef: heading such as "Definitions", "Words and Phrases Defined", or coverage-specific definition section
|
|
5386
|
+
- originalContent: short verbatim source snippet containing the term and definition
|
|
5387
|
+
|
|
5388
|
+
Focus on:
|
|
5389
|
+
- Terms in sections titled Definitions, Words and Phrases Defined, Glossary, or similar
|
|
5390
|
+
- Coverage-specific defined terms embedded in insuring agreements, endorsements, exclusions, or conditions
|
|
5391
|
+
- Multi-part definitions with numbered, lettered, or bulleted clauses
|
|
5392
|
+
- Definitions that affect coverage triggers, covered property, insured status, exclusions, limits, or duties
|
|
5393
|
+
|
|
5394
|
+
Critical rules:
|
|
5395
|
+
- Preserve the original content. Do not paraphrase content.
|
|
5396
|
+
- Keep all subparts of a definition together in one item when they define the same term.
|
|
5397
|
+
- Ignore table-of-contents entries, running headers/footers, indexes, and cross-references that do not include substantive definition text.
|
|
5398
|
+
- Do not emit generic headings like "Definitions" as a term unless the page defines an actual term.
|
|
5399
|
+
- Always include pageNumber when the definition appears on a specific page in the supplied document chunk.
|
|
5400
|
+
- Use definition as the canonical full text. Do not return a separate content field.
|
|
5401
|
+
|
|
5402
|
+
Return JSON only.`;
|
|
5403
|
+
}
|
|
5404
|
+
|
|
5405
|
+
// src/prompts/extractors/covered-reasons.ts
|
|
5406
|
+
import { z as z35 } from "zod";
|
|
5407
|
+
var CoveredReasonsSchema = z35.object({
|
|
5408
|
+
coveredReasons: z35.array(
|
|
5409
|
+
z35.object({
|
|
5410
|
+
coverageName: z35.string().describe("Coverage, coverage part, or form this covered reason belongs to"),
|
|
5411
|
+
reasonNumber: z35.string().optional().describe("Source number or letter for the covered reason, if shown"),
|
|
5412
|
+
title: z35.string().optional().describe("Covered reason title, peril, cause of loss, trigger, or short name"),
|
|
5413
|
+
content: z35.string().describe("Full verbatim covered-reason or insuring-agreement text"),
|
|
5414
|
+
conditions: z35.array(z35.string()).optional().describe("Conditions, timing rules, documentation requirements, or prerequisites attached to this covered reason"),
|
|
5415
|
+
exceptions: z35.array(z35.string()).optional().describe("Exceptions or limitations attached to this covered reason"),
|
|
5416
|
+
appliesTo: z35.array(z35.string()).optional().describe("Covered property, persons, autos, locations, operations, or coverage parts this reason applies to"),
|
|
5417
|
+
pageNumber: z35.number().optional().describe("Original document page number"),
|
|
5418
|
+
formNumber: z35.string().optional().describe("Form number where this covered reason appears"),
|
|
5419
|
+
formTitle: z35.string().optional().describe("Form title where this covered reason appears"),
|
|
5420
|
+
sectionRef: z35.string().optional().describe("Section heading where this covered reason appears"),
|
|
5421
|
+
originalContent: z35.string().optional().describe("Short verbatim source snippet used for this covered reason")
|
|
5422
|
+
})
|
|
5423
|
+
).describe("Covered causes, perils, triggers, or reasons that affirmatively grant coverage")
|
|
5424
|
+
});
|
|
5425
|
+
function buildCoveredReasonsPrompt() {
|
|
5426
|
+
return `You are an expert insurance document analyst. Extract ALL covered reasons from this document. Preserve original wording verbatim.
|
|
5427
|
+
|
|
5428
|
+
A covered reason is affirmative coverage language explaining why, when, or for what cause the insurer will pay. This may be called a covered peril, covered cause of loss, accident, occurrence, loss trigger, additional coverage, expense, or insuring agreement grant.
|
|
5429
|
+
|
|
5430
|
+
For EACH covered reason, extract:
|
|
5431
|
+
- coverageName: coverage, coverage part, or form this covered reason belongs to \u2014 REQUIRED
|
|
5432
|
+
- reasonNumber: source number or letter for the covered reason, if shown
|
|
5433
|
+
- title: covered peril, cause of loss, trigger, or short name
|
|
5434
|
+
- content: full verbatim covered-reason or insuring-agreement text \u2014 REQUIRED
|
|
5435
|
+
- conditions: conditions, timing rules, documentation requirements, or prerequisites attached to this covered reason
|
|
5436
|
+
- exceptions: exceptions or limitations attached to this covered reason
|
|
5437
|
+
- appliesTo: covered property, persons, autos, locations, operations, or coverage parts this reason applies to
|
|
5438
|
+
- pageNumber: original document page number where this covered reason appears
|
|
5439
|
+
- formNumber: form number where this covered reason appears, if shown
|
|
5440
|
+
- formTitle: form title where this covered reason appears, if shown
|
|
5441
|
+
- sectionRef: heading where this covered reason appears
|
|
5442
|
+
- originalContent: short verbatim source snippet used for this covered reason
|
|
5443
|
+
|
|
5444
|
+
Focus on:
|
|
5445
|
+
- Named perils and covered causes of loss
|
|
5446
|
+
- Insuring agreement grants and coverage triggers
|
|
5447
|
+
- Additional coverages and coverage extensions that state when payment applies
|
|
5448
|
+
- Personal lines phrases such as fire, lightning, windstorm, hail, theft, collision, comprehensive, or accidental direct physical loss
|
|
5449
|
+
- Commercial lines phrases such as bodily injury, property damage, personal and advertising injury, employee dishonesty, computer fraud, equipment breakdown, or professional services acts
|
|
5450
|
+
|
|
5451
|
+
Critical rules:
|
|
5452
|
+
- Preserve the original content. Do not paraphrase content.
|
|
5453
|
+
- Extract affirmative coverage grants, not exclusions, conditions, or declarations-only limit rows.
|
|
5454
|
+
- Do not emit a covered reason from a table-of-contents entry, running header/footer, or reference that only points elsewhere.
|
|
5455
|
+
- If a covered reason includes exceptions or limitations in the same clause, keep them in content and also list them in exceptions when they can be separated cleanly.
|
|
5456
|
+
- Always include pageNumber when the covered reason appears on a specific page in the supplied document chunk.
|
|
5457
|
+
- Preserve coverage grouping. Do not merge separate coverage parts into one generic list.
|
|
5458
|
+
|
|
5459
|
+
Return JSON only.`;
|
|
5460
|
+
}
|
|
5461
|
+
|
|
5008
5462
|
// src/prompts/extractors/index.ts
|
|
5009
5463
|
var EXTRACTORS = {
|
|
5010
5464
|
carrier_info: { buildPrompt: buildCarrierInfoPrompt, schema: CarrierInfoSchema, maxTokens: 2048 },
|
|
@@ -5017,28 +5471,30 @@ var EXTRACTORS = {
|
|
|
5017
5471
|
declarations: { buildPrompt: buildDeclarationsPrompt, schema: DeclarationsExtractSchema, maxTokens: 8192 },
|
|
5018
5472
|
loss_history: { buildPrompt: buildLossHistoryPrompt, schema: LossHistorySchema, maxTokens: 4096 },
|
|
5019
5473
|
sections: { buildPrompt: buildSectionsPrompt, schema: SectionsSchema, maxTokens: 8192 },
|
|
5020
|
-
supplementary: { buildPrompt: buildSupplementaryPrompt, schema: SupplementarySchema, maxTokens: 2048 }
|
|
5474
|
+
supplementary: { buildPrompt: buildSupplementaryPrompt, schema: SupplementarySchema, maxTokens: 2048 },
|
|
5475
|
+
definitions: { buildPrompt: buildDefinitionsPrompt, schema: DefinitionsSchema, maxTokens: 8192 },
|
|
5476
|
+
covered_reasons: { buildPrompt: buildCoveredReasonsPrompt, schema: CoveredReasonsSchema, maxTokens: 8192 }
|
|
5021
5477
|
};
|
|
5022
5478
|
function getExtractor(name) {
|
|
5023
5479
|
return EXTRACTORS[name];
|
|
5024
5480
|
}
|
|
5025
5481
|
|
|
5026
5482
|
// src/extraction/resolve-referential.ts
|
|
5027
|
-
import { z as
|
|
5483
|
+
import { z as z37 } from "zod";
|
|
5028
5484
|
|
|
5029
5485
|
// src/prompts/extractors/referential-lookup.ts
|
|
5030
|
-
import { z as
|
|
5031
|
-
var ReferentialLookupSchema =
|
|
5032
|
-
resolvedCoverages:
|
|
5033
|
-
|
|
5034
|
-
coverageName:
|
|
5035
|
-
resolvedLimit:
|
|
5486
|
+
import { z as z36 } from "zod";
|
|
5487
|
+
var ReferentialLookupSchema = z36.object({
|
|
5488
|
+
resolvedCoverages: z36.array(
|
|
5489
|
+
z36.object({
|
|
5490
|
+
coverageName: z36.string().describe("The coverage name that was referenced"),
|
|
5491
|
+
resolvedLimit: z36.string().optional().describe("The concrete limit value found, if any"),
|
|
5036
5492
|
resolvedLimitValueType: CoverageValueTypeSchema.optional(),
|
|
5037
|
-
resolvedDeductible:
|
|
5493
|
+
resolvedDeductible: z36.string().optional().describe("The concrete deductible value found, if any"),
|
|
5038
5494
|
resolvedDeductibleValueType: CoverageValueTypeSchema.optional(),
|
|
5039
|
-
pageNumber:
|
|
5040
|
-
originalContent:
|
|
5041
|
-
confidence:
|
|
5495
|
+
pageNumber: z36.number().optional().describe("Page where the resolved value was found"),
|
|
5496
|
+
originalContent: z36.string().optional().describe("Verbatim source text for the resolved value"),
|
|
5497
|
+
confidence: z36.enum(["high", "medium", "low"]).describe("Confidence in the resolution")
|
|
5042
5498
|
})
|
|
5043
5499
|
)
|
|
5044
5500
|
});
|
|
@@ -5097,9 +5553,9 @@ function parseReferenceTarget(text) {
|
|
|
5097
5553
|
if (/if applicable/i.test(normalized)) return void 0;
|
|
5098
5554
|
return void 0;
|
|
5099
5555
|
}
|
|
5100
|
-
var PageLocationSchema =
|
|
5101
|
-
startPage:
|
|
5102
|
-
endPage:
|
|
5556
|
+
var PageLocationSchema = z37.object({
|
|
5557
|
+
startPage: z37.number(),
|
|
5558
|
+
endPage: z37.number()
|
|
5103
5559
|
});
|
|
5104
5560
|
async function findReferencedPages(params) {
|
|
5105
5561
|
const {
|
|
@@ -5419,6 +5875,32 @@ function buildExtractionReviewReport(params) {
|
|
|
5419
5875
|
const exclusions = memory.get("exclusions")?.exclusions ?? [];
|
|
5420
5876
|
const conditions = memory.get("conditions")?.conditions ?? [];
|
|
5421
5877
|
const sections = memory.get("sections")?.sections ?? [];
|
|
5878
|
+
const definitionsResult = memory.get("definitions");
|
|
5879
|
+
const coveredReasonsResult = memory.get("covered_reasons");
|
|
5880
|
+
const definitions = Array.isArray(definitionsResult?.definitions) ? definitionsResult.definitions : sections.filter((section) => section.type === "definition");
|
|
5881
|
+
const coveredReasons = Array.isArray(coveredReasonsResult?.coveredReasons) ? coveredReasonsResult.coveredReasons : Array.isArray(coveredReasonsResult?.covered_reasons) ? coveredReasonsResult.covered_reasons : sections.filter((section) => {
|
|
5882
|
+
const title = String(section.title ?? "").toLowerCase();
|
|
5883
|
+
const type = String(section.type ?? "").toLowerCase();
|
|
5884
|
+
return type === "covered_reason" || title.includes("covered cause") || title.includes("covered reason") || title.includes("covered peril");
|
|
5885
|
+
});
|
|
5886
|
+
const mappedDefinitions = params.pageAssignments.some((assignment) => assignment.extractorNames.includes("definitions"));
|
|
5887
|
+
const mappedCoveredReasons = params.pageAssignments.some((assignment) => assignment.extractorNames.includes("covered_reasons"));
|
|
5888
|
+
if (mappedDefinitions && definitions.length === 0) {
|
|
5889
|
+
deterministicIssues.push({
|
|
5890
|
+
code: "definitions_mapped_but_empty",
|
|
5891
|
+
severity: "warning",
|
|
5892
|
+
message: "Page map assigned definitions extraction, but no definition records were extracted.",
|
|
5893
|
+
extractorName: "definitions"
|
|
5894
|
+
});
|
|
5895
|
+
}
|
|
5896
|
+
if (mappedCoveredReasons && coveredReasons.length === 0) {
|
|
5897
|
+
deterministicIssues.push({
|
|
5898
|
+
code: "covered_reasons_mapped_but_empty",
|
|
5899
|
+
severity: "warning",
|
|
5900
|
+
message: "Page map assigned covered reasons extraction, but no covered reason records were extracted.",
|
|
5901
|
+
extractorName: "covered_reasons"
|
|
5902
|
+
});
|
|
5903
|
+
}
|
|
5422
5904
|
for (const form of extractedFormInventory) {
|
|
5423
5905
|
addFormEntry(
|
|
5424
5906
|
inventory,
|
|
@@ -5616,6 +6098,67 @@ function buildExtractionReviewReport(params) {
|
|
|
5616
6098
|
});
|
|
5617
6099
|
}
|
|
5618
6100
|
}
|
|
6101
|
+
for (const definition of definitions) {
|
|
6102
|
+
const term = typeof definition.term === "string" ? definition.term : typeof definition.title === "string" ? definition.title : "unknown";
|
|
6103
|
+
const content = typeof definition.definition === "string" ? definition.definition : typeof definition.content === "string" ? definition.content : "";
|
|
6104
|
+
if (!content.trim()) {
|
|
6105
|
+
deterministicIssues.push({
|
|
6106
|
+
code: "definition_missing_content",
|
|
6107
|
+
severity: "warning",
|
|
6108
|
+
message: `Definition "${term}" is missing definition text.`,
|
|
6109
|
+
extractorName: "definitions",
|
|
6110
|
+
formNumber: normalizeFormNumber(definition.formNumber),
|
|
6111
|
+
pageNumber: typeof definition.pageNumber === "number" ? definition.pageNumber : typeof definition.pageStart === "number" ? definition.pageStart : void 0,
|
|
6112
|
+
itemName: term
|
|
6113
|
+
});
|
|
6114
|
+
}
|
|
6115
|
+
if (typeof definition.pageNumber !== "number" && typeof definition.pageStart !== "number") {
|
|
6116
|
+
deterministicIssues.push({
|
|
6117
|
+
code: "definition_missing_page_number",
|
|
6118
|
+
severity: "warning",
|
|
6119
|
+
message: `Definition "${term}" is missing page provenance.`,
|
|
6120
|
+
extractorName: "definitions",
|
|
6121
|
+
formNumber: normalizeFormNumber(definition.formNumber),
|
|
6122
|
+
itemName: term
|
|
6123
|
+
});
|
|
6124
|
+
}
|
|
6125
|
+
}
|
|
6126
|
+
for (const coveredReason of coveredReasons) {
|
|
6127
|
+
const itemName = typeof coveredReason.name === "string" ? coveredReason.name : typeof coveredReason.reason === "string" ? coveredReason.reason : typeof coveredReason.title === "string" ? coveredReason.title : "unknown";
|
|
6128
|
+
const content = typeof coveredReason.content === "string" ? coveredReason.content : typeof coveredReason.description === "string" ? coveredReason.description : "";
|
|
6129
|
+
if (!content.trim()) {
|
|
6130
|
+
deterministicIssues.push({
|
|
6131
|
+
code: "covered_reason_missing_content",
|
|
6132
|
+
severity: "warning",
|
|
6133
|
+
message: `Covered reason "${itemName}" is missing substantive text.`,
|
|
6134
|
+
extractorName: "covered_reasons",
|
|
6135
|
+
formNumber: normalizeFormNumber(coveredReason.formNumber),
|
|
6136
|
+
pageNumber: typeof coveredReason.pageNumber === "number" ? coveredReason.pageNumber : typeof coveredReason.pageStart === "number" ? coveredReason.pageStart : void 0,
|
|
6137
|
+
itemName
|
|
6138
|
+
});
|
|
6139
|
+
}
|
|
6140
|
+
if (typeof coveredReason.pageNumber !== "number" && typeof coveredReason.pageStart !== "number") {
|
|
6141
|
+
deterministicIssues.push({
|
|
6142
|
+
code: "covered_reason_missing_page_number",
|
|
6143
|
+
severity: "warning",
|
|
6144
|
+
message: `Covered reason "${itemName}" is missing page provenance.`,
|
|
6145
|
+
extractorName: "covered_reasons",
|
|
6146
|
+
formNumber: normalizeFormNumber(coveredReason.formNumber),
|
|
6147
|
+
itemName
|
|
6148
|
+
});
|
|
6149
|
+
}
|
|
6150
|
+
if (looksReferential2(content) || looksReferential2(coveredReason.reason)) {
|
|
6151
|
+
deterministicIssues.push({
|
|
6152
|
+
code: "covered_reason_referential_value",
|
|
6153
|
+
severity: "warning",
|
|
6154
|
+
message: `Covered reason "${itemName}" contains referential language instead of the extracted covered cause wording.`,
|
|
6155
|
+
extractorName: "covered_reasons",
|
|
6156
|
+
formNumber: normalizeFormNumber(coveredReason.formNumber),
|
|
6157
|
+
pageNumber: typeof coveredReason.pageNumber === "number" ? coveredReason.pageNumber : typeof coveredReason.pageStart === "number" ? coveredReason.pageStart : void 0,
|
|
6158
|
+
itemName
|
|
6159
|
+
});
|
|
6160
|
+
}
|
|
6161
|
+
}
|
|
5619
6162
|
for (const section of sections) {
|
|
5620
6163
|
if (typeof section.content === "string" && section.content.trim().length < 120 && typeof section.pageStart === "number" && (!("pageEnd" in section) || section.pageEnd === section.pageStart || section.pageEnd === void 0)) {
|
|
5621
6164
|
deterministicIssues.push({
|
|
@@ -5638,6 +6181,8 @@ function buildExtractionReviewReport(params) {
|
|
|
5638
6181
|
const artifacts = [
|
|
5639
6182
|
{ kind: "form_inventory", label: "Form Inventory", itemCount: formInventory.length },
|
|
5640
6183
|
{ kind: "page_map", label: "Page Map", itemCount: params.pageAssignments.length },
|
|
6184
|
+
{ kind: "definitions", label: "Definitions", itemCount: definitions.length },
|
|
6185
|
+
{ kind: "covered_reasons", label: "Covered Reasons", itemCount: coveredReasons.length },
|
|
5641
6186
|
{ kind: "referential_resolution", label: "Referential Resolution", itemCount: coverages.filter((c) => c.limitValueType === "referential" || c.limitValueType === "as_stated" || c.deductibleValueType === "referential" || c.deductibleValueType === "as_stated").length }
|
|
5642
6187
|
];
|
|
5643
6188
|
const qualityGateStatus = evaluateQualityGate({
|
|
@@ -5705,6 +6250,15 @@ function createExtractor(config) {
|
|
|
5705
6250
|
const exclusionResult = memory.get("exclusions");
|
|
5706
6251
|
const conditionResult = memory.get("conditions");
|
|
5707
6252
|
const sectionResult = memory.get("sections");
|
|
6253
|
+
const definitionsResult = memory.get("definitions");
|
|
6254
|
+
const coveredReasonsResult = memory.get("covered_reasons");
|
|
6255
|
+
const sections = Array.isArray(sectionResult?.sections) ? sectionResult.sections : [];
|
|
6256
|
+
const definitionCount = Array.isArray(definitionsResult?.definitions) ? definitionsResult.definitions.length : sections.filter((section) => section.type === "definition").length;
|
|
6257
|
+
const coveredReasonCount = Array.isArray(coveredReasonsResult?.coveredReasons) ? coveredReasonsResult.coveredReasons.length : Array.isArray(coveredReasonsResult?.covered_reasons) ? coveredReasonsResult.covered_reasons.length : sections.filter((section) => {
|
|
6258
|
+
const title = String(section.title ?? "").toLowerCase();
|
|
6259
|
+
const type = String(section.type ?? "").toLowerCase();
|
|
6260
|
+
return type === "covered_reason" || title.includes("covered cause") || title.includes("covered reason") || title.includes("covered peril");
|
|
6261
|
+
}).length;
|
|
5708
6262
|
const coverageSummary = Array.isArray(coverageResult?.coverages) ? coverageResult.coverages.slice(0, 12).map((coverage) => ({
|
|
5709
6263
|
name: coverage.name,
|
|
5710
6264
|
limit: coverage.limit,
|
|
@@ -5719,7 +6273,9 @@ function createExtractor(config) {
|
|
|
5719
6273
|
endorsementCount: Array.isArray(endorsementResult?.endorsements) ? endorsementResult.endorsements.length : 0,
|
|
5720
6274
|
exclusionCount: Array.isArray(exclusionResult?.exclusions) ? exclusionResult.exclusions.length : 0,
|
|
5721
6275
|
conditionCount: Array.isArray(conditionResult?.conditions) ? conditionResult.conditions.length : 0,
|
|
5722
|
-
|
|
6276
|
+
definitionCount,
|
|
6277
|
+
coveredReasonCount,
|
|
6278
|
+
sectionCount: sections.length
|
|
5723
6279
|
}, null, 2);
|
|
5724
6280
|
}
|
|
5725
6281
|
function buildAlreadyExtractedSummary(memory) {
|
|
@@ -5762,7 +6318,7 @@ function createExtractor(config) {
|
|
|
5762
6318
|
}
|
|
5763
6319
|
}
|
|
5764
6320
|
if (extractorPages.size === 0) return "No page assignments available.";
|
|
5765
|
-
return [...extractorPages.entries()].map(([extractorName, pages]) => `${extractorName}: pages ${pages.join(", ")}`).join("\n");
|
|
6321
|
+
return [...extractorPages.entries()].map(([extractorName, pages]) => `${extractorName}: ${pages.length} page(s), pages ${pages.join(", ")}`).join("\n");
|
|
5766
6322
|
}
|
|
5767
6323
|
function normalizePageAssignments(pageAssignments, formInventory) {
|
|
5768
6324
|
const pageFormTypes = /* @__PURE__ */ new Map();
|
|
@@ -5852,7 +6408,7 @@ function createExtractor(config) {
|
|
|
5852
6408
|
extractorPages.set("sections", [...extractorPages.get("sections") ?? [], page]);
|
|
5853
6409
|
}
|
|
5854
6410
|
}
|
|
5855
|
-
const contextualExtractors = /* @__PURE__ */ new Set(["conditions", "exclusions", "endorsements"]);
|
|
6411
|
+
const contextualExtractors = /* @__PURE__ */ new Set(["conditions", "covered_reasons", "definitions", "exclusions", "endorsements"]);
|
|
5856
6412
|
const contextualForms = (formInventory?.forms ?? []).filter(
|
|
5857
6413
|
(form) => form.pageStart != null && (form.pageEnd ?? form.pageStart) != null
|
|
5858
6414
|
);
|
|
@@ -6068,7 +6624,7 @@ function createExtractor(config) {
|
|
|
6068
6624
|
const extractorResults = await Promise.all(
|
|
6069
6625
|
tasks.map(
|
|
6070
6626
|
(task) => limit(async () => {
|
|
6071
|
-
const ext = getExtractor(task.extractorName);
|
|
6627
|
+
const ext = getExtractor(task.extractorName) ?? (task.extractorName === "definitions" || task.extractorName === "covered_reasons" ? getExtractor("sections") : void 0);
|
|
6072
6628
|
if (!ext) {
|
|
6073
6629
|
await log?.(`Unknown extractor: ${task.extractorName}, skipping`);
|
|
6074
6630
|
return null;
|
|
@@ -6199,7 +6755,7 @@ function createExtractor(config) {
|
|
|
6199
6755
|
const followUpResults = await Promise.all(
|
|
6200
6756
|
reviewResponse.object.additionalTasks.map(
|
|
6201
6757
|
(task) => limit(async () => {
|
|
6202
|
-
const ext = getExtractor(task.extractorName);
|
|
6758
|
+
const ext = getExtractor(task.extractorName) ?? (task.extractorName === "definitions" || task.extractorName === "covered_reasons" ? getExtractor("sections") : void 0);
|
|
6203
6759
|
if (!ext) return null;
|
|
6204
6760
|
try {
|
|
6205
6761
|
const result = await runExtractor({
|
|
@@ -6442,7 +6998,7 @@ function buildQuotesPoliciesPrompt() {
|
|
|
6442
6998
|
return `POLICIES vs QUOTES:
|
|
6443
6999
|
- POLICIES = bound coverage currently in force. Use these when answering "what coverage do we have?", "what are our limits?", "are we covered for X?"
|
|
6444
7000
|
- QUOTES = proposals or indications received but not yet bound. Use these when answering "what quotes have we received?", "what was quoted?", "what are the proposed terms?"
|
|
6445
|
-
- Always clearly label which you are referencing. Say "In your [
|
|
7001
|
+
- Always clearly label which you are referencing. Refer to policies and quotes by the ADMINISTRATOR / MGA (the \`mga\` field) when present \u2014 this is the entity the insured actually interacts with. Only fall back to the carrier name if no administrator/MGA is available. Say "In your [administrator] policy..." or "In the [administrator] quote/proposal...". Do not lead with the underlying carrier (e.g. "CUMIS General Insurance Company") when an administrator/MGA like "Allianz Global Assistance" is available.
|
|
6446
7002
|
- NEVER present a quote as active coverage. A quote is a proposal only.
|
|
6447
7003
|
- If asked about coverage, default to policies unless the question specifically asks about quotes or proposals.
|
|
6448
7004
|
|
|
@@ -6539,8 +7095,8 @@ Respond with JSON only:
|
|
|
6539
7095
|
}`;
|
|
6540
7096
|
|
|
6541
7097
|
// src/schemas/application.ts
|
|
6542
|
-
import { z as
|
|
6543
|
-
var FieldTypeSchema =
|
|
7098
|
+
import { z as z38 } from "zod";
|
|
7099
|
+
var FieldTypeSchema = z38.enum([
|
|
6544
7100
|
"text",
|
|
6545
7101
|
"numeric",
|
|
6546
7102
|
"currency",
|
|
@@ -6549,131 +7105,131 @@ var FieldTypeSchema = z36.enum([
|
|
|
6549
7105
|
"table",
|
|
6550
7106
|
"declaration"
|
|
6551
7107
|
]);
|
|
6552
|
-
var ApplicationFieldSchema =
|
|
6553
|
-
id:
|
|
6554
|
-
label:
|
|
6555
|
-
section:
|
|
7108
|
+
var ApplicationFieldSchema = z38.object({
|
|
7109
|
+
id: z38.string(),
|
|
7110
|
+
label: z38.string(),
|
|
7111
|
+
section: z38.string(),
|
|
6556
7112
|
fieldType: FieldTypeSchema,
|
|
6557
|
-
required:
|
|
6558
|
-
options:
|
|
6559
|
-
columns:
|
|
6560
|
-
requiresExplanationIfYes:
|
|
6561
|
-
condition:
|
|
6562
|
-
dependsOn:
|
|
6563
|
-
whenValue:
|
|
7113
|
+
required: z38.boolean(),
|
|
7114
|
+
options: z38.array(z38.string()).optional(),
|
|
7115
|
+
columns: z38.array(z38.string()).optional(),
|
|
7116
|
+
requiresExplanationIfYes: z38.boolean().optional(),
|
|
7117
|
+
condition: z38.object({
|
|
7118
|
+
dependsOn: z38.string(),
|
|
7119
|
+
whenValue: z38.string()
|
|
6564
7120
|
}).optional(),
|
|
6565
|
-
value:
|
|
6566
|
-
source:
|
|
6567
|
-
confidence:
|
|
6568
|
-
});
|
|
6569
|
-
var ApplicationClassifyResultSchema =
|
|
6570
|
-
isApplication:
|
|
6571
|
-
confidence:
|
|
6572
|
-
applicationType:
|
|
6573
|
-
});
|
|
6574
|
-
var FieldExtractionResultSchema =
|
|
6575
|
-
fields:
|
|
6576
|
-
});
|
|
6577
|
-
var AutoFillMatchSchema =
|
|
6578
|
-
fieldId:
|
|
6579
|
-
value:
|
|
6580
|
-
confidence:
|
|
6581
|
-
contextKey:
|
|
6582
|
-
});
|
|
6583
|
-
var AutoFillResultSchema =
|
|
6584
|
-
matches:
|
|
6585
|
-
});
|
|
6586
|
-
var QuestionBatchResultSchema =
|
|
6587
|
-
batches:
|
|
6588
|
-
});
|
|
6589
|
-
var LookupRequestSchema =
|
|
6590
|
-
type:
|
|
6591
|
-
description:
|
|
6592
|
-
url:
|
|
6593
|
-
targetFieldIds:
|
|
6594
|
-
});
|
|
6595
|
-
var ReplyIntentSchema =
|
|
6596
|
-
primaryIntent:
|
|
6597
|
-
hasAnswers:
|
|
6598
|
-
questionText:
|
|
6599
|
-
questionFieldIds:
|
|
6600
|
-
lookupRequests:
|
|
6601
|
-
});
|
|
6602
|
-
var ParsedAnswerSchema =
|
|
6603
|
-
fieldId:
|
|
6604
|
-
value:
|
|
6605
|
-
explanation:
|
|
6606
|
-
});
|
|
6607
|
-
var AnswerParsingResultSchema =
|
|
6608
|
-
answers:
|
|
6609
|
-
unanswered:
|
|
6610
|
-
});
|
|
6611
|
-
var LookupFillSchema =
|
|
6612
|
-
fieldId:
|
|
6613
|
-
value:
|
|
6614
|
-
source:
|
|
6615
|
-
});
|
|
6616
|
-
var LookupFillResultSchema =
|
|
6617
|
-
fills:
|
|
6618
|
-
unfillable:
|
|
6619
|
-
explanation:
|
|
6620
|
-
});
|
|
6621
|
-
var FlatPdfPlacementSchema =
|
|
6622
|
-
fieldId:
|
|
6623
|
-
page:
|
|
6624
|
-
x:
|
|
6625
|
-
y:
|
|
6626
|
-
text:
|
|
6627
|
-
fontSize:
|
|
6628
|
-
isCheckmark:
|
|
6629
|
-
});
|
|
6630
|
-
var AcroFormMappingSchema =
|
|
6631
|
-
fieldId:
|
|
6632
|
-
acroFormName:
|
|
6633
|
-
value:
|
|
6634
|
-
});
|
|
6635
|
-
var QualityGateStatusSchema =
|
|
6636
|
-
var QualitySeveritySchema =
|
|
6637
|
-
var ApplicationQualityIssueSchema =
|
|
6638
|
-
code:
|
|
7121
|
+
value: z38.string().optional(),
|
|
7122
|
+
source: z38.string().optional().describe("Where the value came from: auto-fill, user, lookup"),
|
|
7123
|
+
confidence: z38.enum(["confirmed", "high", "medium", "low"]).optional()
|
|
7124
|
+
});
|
|
7125
|
+
var ApplicationClassifyResultSchema = z38.object({
|
|
7126
|
+
isApplication: z38.boolean(),
|
|
7127
|
+
confidence: z38.number().min(0).max(1),
|
|
7128
|
+
applicationType: z38.string().nullable()
|
|
7129
|
+
});
|
|
7130
|
+
var FieldExtractionResultSchema = z38.object({
|
|
7131
|
+
fields: z38.array(ApplicationFieldSchema)
|
|
7132
|
+
});
|
|
7133
|
+
var AutoFillMatchSchema = z38.object({
|
|
7134
|
+
fieldId: z38.string(),
|
|
7135
|
+
value: z38.string(),
|
|
7136
|
+
confidence: z38.enum(["confirmed"]),
|
|
7137
|
+
contextKey: z38.string()
|
|
7138
|
+
});
|
|
7139
|
+
var AutoFillResultSchema = z38.object({
|
|
7140
|
+
matches: z38.array(AutoFillMatchSchema)
|
|
7141
|
+
});
|
|
7142
|
+
var QuestionBatchResultSchema = z38.object({
|
|
7143
|
+
batches: z38.array(z38.array(z38.string()).describe("Array of field IDs in this batch"))
|
|
7144
|
+
});
|
|
7145
|
+
var LookupRequestSchema = z38.object({
|
|
7146
|
+
type: z38.string().describe("Type of lookup: 'records', 'website', 'policy'"),
|
|
7147
|
+
description: z38.string(),
|
|
7148
|
+
url: z38.string().optional(),
|
|
7149
|
+
targetFieldIds: z38.array(z38.string())
|
|
7150
|
+
});
|
|
7151
|
+
var ReplyIntentSchema = z38.object({
|
|
7152
|
+
primaryIntent: z38.enum(["answers_only", "question", "lookup_request", "mixed"]),
|
|
7153
|
+
hasAnswers: z38.boolean(),
|
|
7154
|
+
questionText: z38.string().optional(),
|
|
7155
|
+
questionFieldIds: z38.array(z38.string()).optional(),
|
|
7156
|
+
lookupRequests: z38.array(LookupRequestSchema).optional()
|
|
7157
|
+
});
|
|
7158
|
+
var ParsedAnswerSchema = z38.object({
|
|
7159
|
+
fieldId: z38.string(),
|
|
7160
|
+
value: z38.string(),
|
|
7161
|
+
explanation: z38.string().optional()
|
|
7162
|
+
});
|
|
7163
|
+
var AnswerParsingResultSchema = z38.object({
|
|
7164
|
+
answers: z38.array(ParsedAnswerSchema),
|
|
7165
|
+
unanswered: z38.array(z38.string()).describe("Field IDs that were not answered")
|
|
7166
|
+
});
|
|
7167
|
+
var LookupFillSchema = z38.object({
|
|
7168
|
+
fieldId: z38.string(),
|
|
7169
|
+
value: z38.string(),
|
|
7170
|
+
source: z38.string().describe("Specific citable reference, e.g. 'GL Policy #POL-12345 (Hartford)'")
|
|
7171
|
+
});
|
|
7172
|
+
var LookupFillResultSchema = z38.object({
|
|
7173
|
+
fills: z38.array(LookupFillSchema),
|
|
7174
|
+
unfillable: z38.array(z38.string()),
|
|
7175
|
+
explanation: z38.string().optional()
|
|
7176
|
+
});
|
|
7177
|
+
var FlatPdfPlacementSchema = z38.object({
|
|
7178
|
+
fieldId: z38.string(),
|
|
7179
|
+
page: z38.number(),
|
|
7180
|
+
x: z38.number().describe("Percentage from left edge (0-100)"),
|
|
7181
|
+
y: z38.number().describe("Percentage from top edge (0-100)"),
|
|
7182
|
+
text: z38.string(),
|
|
7183
|
+
fontSize: z38.number().optional(),
|
|
7184
|
+
isCheckmark: z38.boolean().optional()
|
|
7185
|
+
});
|
|
7186
|
+
var AcroFormMappingSchema = z38.object({
|
|
7187
|
+
fieldId: z38.string(),
|
|
7188
|
+
acroFormName: z38.string(),
|
|
7189
|
+
value: z38.string()
|
|
7190
|
+
});
|
|
7191
|
+
var QualityGateStatusSchema = z38.enum(["passed", "warning", "failed"]);
|
|
7192
|
+
var QualitySeveritySchema = z38.enum(["info", "warning", "blocking"]);
|
|
7193
|
+
var ApplicationQualityIssueSchema = z38.object({
|
|
7194
|
+
code: z38.string(),
|
|
6639
7195
|
severity: QualitySeveritySchema,
|
|
6640
|
-
message:
|
|
6641
|
-
fieldId:
|
|
7196
|
+
message: z38.string(),
|
|
7197
|
+
fieldId: z38.string().optional()
|
|
6642
7198
|
});
|
|
6643
|
-
var ApplicationQualityRoundSchema =
|
|
6644
|
-
round:
|
|
6645
|
-
kind:
|
|
7199
|
+
var ApplicationQualityRoundSchema = z38.object({
|
|
7200
|
+
round: z38.number(),
|
|
7201
|
+
kind: z38.string(),
|
|
6646
7202
|
status: QualityGateStatusSchema,
|
|
6647
|
-
summary:
|
|
7203
|
+
summary: z38.string().optional()
|
|
6648
7204
|
});
|
|
6649
|
-
var ApplicationQualityArtifactSchema =
|
|
6650
|
-
kind:
|
|
6651
|
-
label:
|
|
6652
|
-
itemCount:
|
|
7205
|
+
var ApplicationQualityArtifactSchema = z38.object({
|
|
7206
|
+
kind: z38.string(),
|
|
7207
|
+
label: z38.string().optional(),
|
|
7208
|
+
itemCount: z38.number().optional()
|
|
6653
7209
|
});
|
|
6654
|
-
var ApplicationEmailReviewSchema =
|
|
6655
|
-
issues:
|
|
7210
|
+
var ApplicationEmailReviewSchema = z38.object({
|
|
7211
|
+
issues: z38.array(ApplicationQualityIssueSchema),
|
|
6656
7212
|
qualityGateStatus: QualityGateStatusSchema
|
|
6657
7213
|
});
|
|
6658
|
-
var ApplicationQualityReportSchema =
|
|
6659
|
-
issues:
|
|
6660
|
-
rounds:
|
|
6661
|
-
artifacts:
|
|
7214
|
+
var ApplicationQualityReportSchema = z38.object({
|
|
7215
|
+
issues: z38.array(ApplicationQualityIssueSchema),
|
|
7216
|
+
rounds: z38.array(ApplicationQualityRoundSchema).optional(),
|
|
7217
|
+
artifacts: z38.array(ApplicationQualityArtifactSchema).optional(),
|
|
6662
7218
|
emailReview: ApplicationEmailReviewSchema.optional(),
|
|
6663
7219
|
qualityGateStatus: QualityGateStatusSchema
|
|
6664
7220
|
});
|
|
6665
|
-
var ApplicationStateSchema =
|
|
6666
|
-
id:
|
|
6667
|
-
pdfBase64:
|
|
6668
|
-
title:
|
|
6669
|
-
applicationType:
|
|
6670
|
-
fields:
|
|
6671
|
-
batches:
|
|
6672
|
-
currentBatchIndex:
|
|
7221
|
+
var ApplicationStateSchema = z38.object({
|
|
7222
|
+
id: z38.string(),
|
|
7223
|
+
pdfBase64: z38.string().optional().describe("Original PDF, omitted after extraction"),
|
|
7224
|
+
title: z38.string().optional(),
|
|
7225
|
+
applicationType: z38.string().nullable().optional(),
|
|
7226
|
+
fields: z38.array(ApplicationFieldSchema),
|
|
7227
|
+
batches: z38.array(z38.array(z38.string())).optional(),
|
|
7228
|
+
currentBatchIndex: z38.number().default(0),
|
|
6673
7229
|
qualityReport: ApplicationQualityReportSchema.optional(),
|
|
6674
|
-
status:
|
|
6675
|
-
createdAt:
|
|
6676
|
-
updatedAt:
|
|
7230
|
+
status: z38.enum(["classifying", "extracting", "auto_filling", "batching", "collecting", "confirming", "mapping", "complete"]),
|
|
7231
|
+
createdAt: z38.number(),
|
|
7232
|
+
updatedAt: z38.number()
|
|
6677
7233
|
});
|
|
6678
7234
|
|
|
6679
7235
|
// src/application/agents/classifier.ts
|
|
@@ -7779,7 +8335,7 @@ INSTRUCTIONS:
|
|
|
7779
8335
|
- If the user's attachment already contains critical facts, still request chunk/document lookup when policy or quote details should be cross-checked against stored records
|
|
7780
8336
|
|
|
7781
8337
|
CHUNK TYPES (for chunkTypes filter):
|
|
7782
|
-
carrier_info, named_insured, coverage, endorsement, exclusion, condition, section, declaration, loss_history, premium, supplementary
|
|
8338
|
+
carrier_info, named_insured, coverage, covered_reason, definition, endorsement, exclusion, condition, section, declaration, loss_history, premium, supplementary
|
|
7783
8339
|
|
|
7784
8340
|
Respond with the structured classification.`;
|
|
7785
8341
|
}
|
|
@@ -7810,91 +8366,91 @@ Respond with the final answer, deduplicated citations array, overall confidence
|
|
|
7810
8366
|
}
|
|
7811
8367
|
|
|
7812
8368
|
// src/schemas/query.ts
|
|
7813
|
-
import { z as
|
|
7814
|
-
var QueryIntentSchema =
|
|
8369
|
+
import { z as z39 } from "zod";
|
|
8370
|
+
var QueryIntentSchema = z39.enum([
|
|
7815
8371
|
"policy_question",
|
|
7816
8372
|
"coverage_comparison",
|
|
7817
8373
|
"document_search",
|
|
7818
8374
|
"claims_inquiry",
|
|
7819
8375
|
"general_knowledge"
|
|
7820
8376
|
]);
|
|
7821
|
-
var QueryAttachmentKindSchema =
|
|
7822
|
-
var QueryAttachmentSchema =
|
|
7823
|
-
id:
|
|
8377
|
+
var QueryAttachmentKindSchema = z39.enum(["image", "pdf", "text"]);
|
|
8378
|
+
var QueryAttachmentSchema = z39.object({
|
|
8379
|
+
id: z39.string().optional().describe("Optional stable attachment ID from the caller"),
|
|
7824
8380
|
kind: QueryAttachmentKindSchema,
|
|
7825
|
-
name:
|
|
7826
|
-
mimeType:
|
|
7827
|
-
base64:
|
|
7828
|
-
text:
|
|
7829
|
-
description:
|
|
7830
|
-
});
|
|
7831
|
-
var SubQuestionSchema =
|
|
7832
|
-
question:
|
|
8381
|
+
name: z39.string().optional().describe("Original filename or user-facing label"),
|
|
8382
|
+
mimeType: z39.string().optional().describe("MIME type such as image/jpeg or application/pdf"),
|
|
8383
|
+
base64: z39.string().optional().describe("Base64-encoded file content for image/pdf attachments"),
|
|
8384
|
+
text: z39.string().optional().describe("Plain-text attachment content when available"),
|
|
8385
|
+
description: z39.string().optional().describe("Caller-provided description of the attachment")
|
|
8386
|
+
});
|
|
8387
|
+
var SubQuestionSchema = z39.object({
|
|
8388
|
+
question: z39.string().describe("Atomic sub-question to retrieve and answer independently"),
|
|
7833
8389
|
intent: QueryIntentSchema,
|
|
7834
|
-
chunkTypes:
|
|
7835
|
-
documentFilters:
|
|
7836
|
-
type:
|
|
7837
|
-
carrier:
|
|
7838
|
-
insuredName:
|
|
7839
|
-
policyNumber:
|
|
7840
|
-
quoteNumber:
|
|
7841
|
-
policyTypes:
|
|
8390
|
+
chunkTypes: z39.array(z39.string()).optional().describe("Chunk types to filter retrieval (e.g. coverage, endorsement, declaration)"),
|
|
8391
|
+
documentFilters: z39.object({
|
|
8392
|
+
type: z39.enum(["policy", "quote"]).optional(),
|
|
8393
|
+
carrier: z39.string().optional(),
|
|
8394
|
+
insuredName: z39.string().optional(),
|
|
8395
|
+
policyNumber: z39.string().optional(),
|
|
8396
|
+
quoteNumber: z39.string().optional(),
|
|
8397
|
+
policyTypes: z39.array(PolicyTypeSchema).optional().describe("Filter by policy type (e.g. homeowners_ho3, renters_ho4, pet) to avoid mixing up similar policies")
|
|
7842
8398
|
}).optional().describe("Structured filters to narrow document lookup")
|
|
7843
8399
|
});
|
|
7844
|
-
var QueryClassifyResultSchema =
|
|
8400
|
+
var QueryClassifyResultSchema = z39.object({
|
|
7845
8401
|
intent: QueryIntentSchema,
|
|
7846
|
-
subQuestions:
|
|
7847
|
-
requiresDocumentLookup:
|
|
7848
|
-
requiresChunkSearch:
|
|
7849
|
-
requiresConversationHistory:
|
|
7850
|
-
});
|
|
7851
|
-
var EvidenceItemSchema =
|
|
7852
|
-
source:
|
|
7853
|
-
chunkId:
|
|
7854
|
-
documentId:
|
|
7855
|
-
turnId:
|
|
7856
|
-
attachmentId:
|
|
7857
|
-
text:
|
|
7858
|
-
relevance:
|
|
7859
|
-
metadata:
|
|
7860
|
-
});
|
|
7861
|
-
var AttachmentInterpretationSchema =
|
|
7862
|
-
summary:
|
|
7863
|
-
extractedFacts:
|
|
7864
|
-
recommendedFocus:
|
|
7865
|
-
confidence:
|
|
7866
|
-
});
|
|
7867
|
-
var RetrievalResultSchema =
|
|
7868
|
-
subQuestion:
|
|
7869
|
-
evidence:
|
|
7870
|
-
});
|
|
7871
|
-
var CitationSchema =
|
|
7872
|
-
index:
|
|
7873
|
-
chunkId:
|
|
7874
|
-
documentId:
|
|
7875
|
-
documentType:
|
|
7876
|
-
field:
|
|
7877
|
-
quote:
|
|
7878
|
-
relevance:
|
|
7879
|
-
});
|
|
7880
|
-
var SubAnswerSchema =
|
|
7881
|
-
subQuestion:
|
|
7882
|
-
answer:
|
|
7883
|
-
citations:
|
|
7884
|
-
confidence:
|
|
7885
|
-
needsMoreContext:
|
|
7886
|
-
});
|
|
7887
|
-
var VerifyResultSchema =
|
|
7888
|
-
approved:
|
|
7889
|
-
issues:
|
|
7890
|
-
retrySubQuestions:
|
|
7891
|
-
});
|
|
7892
|
-
var QueryResultSchema =
|
|
7893
|
-
answer:
|
|
7894
|
-
citations:
|
|
8402
|
+
subQuestions: z39.array(SubQuestionSchema).min(1).describe("Decomposed atomic sub-questions"),
|
|
8403
|
+
requiresDocumentLookup: z39.boolean().describe("Whether structured document lookup is needed"),
|
|
8404
|
+
requiresChunkSearch: z39.boolean().describe("Whether semantic chunk search is needed"),
|
|
8405
|
+
requiresConversationHistory: z39.boolean().describe("Whether conversation history is relevant")
|
|
8406
|
+
});
|
|
8407
|
+
var EvidenceItemSchema = z39.object({
|
|
8408
|
+
source: z39.enum(["chunk", "document", "conversation", "attachment"]),
|
|
8409
|
+
chunkId: z39.string().optional(),
|
|
8410
|
+
documentId: z39.string().optional(),
|
|
8411
|
+
turnId: z39.string().optional(),
|
|
8412
|
+
attachmentId: z39.string().optional(),
|
|
8413
|
+
text: z39.string().describe("Text excerpt from the source"),
|
|
8414
|
+
relevance: z39.number().min(0).max(1),
|
|
8415
|
+
metadata: z39.array(z39.object({ key: z39.string(), value: z39.string() })).optional()
|
|
8416
|
+
});
|
|
8417
|
+
var AttachmentInterpretationSchema = z39.object({
|
|
8418
|
+
summary: z39.string().describe("Concise summary of what the attachment shows or contains"),
|
|
8419
|
+
extractedFacts: z39.array(z39.string()).describe("Specific observable or document facts grounded in the attachment"),
|
|
8420
|
+
recommendedFocus: z39.array(z39.string()).describe("Important details to incorporate when answering follow-up questions"),
|
|
8421
|
+
confidence: z39.number().min(0).max(1)
|
|
8422
|
+
});
|
|
8423
|
+
var RetrievalResultSchema = z39.object({
|
|
8424
|
+
subQuestion: z39.string(),
|
|
8425
|
+
evidence: z39.array(EvidenceItemSchema)
|
|
8426
|
+
});
|
|
8427
|
+
var CitationSchema = z39.object({
|
|
8428
|
+
index: z39.number().describe("Citation number [1], [2], etc."),
|
|
8429
|
+
chunkId: z39.string().describe("Source chunk ID, e.g. doc-123:coverage:2"),
|
|
8430
|
+
documentId: z39.string(),
|
|
8431
|
+
documentType: z39.enum(["policy", "quote"]).optional(),
|
|
8432
|
+
field: z39.string().optional().describe("Specific field path, e.g. coverages[0].deductible"),
|
|
8433
|
+
quote: z39.string().describe("Exact text from source that supports the claim"),
|
|
8434
|
+
relevance: z39.number().min(0).max(1)
|
|
8435
|
+
});
|
|
8436
|
+
var SubAnswerSchema = z39.object({
|
|
8437
|
+
subQuestion: z39.string(),
|
|
8438
|
+
answer: z39.string(),
|
|
8439
|
+
citations: z39.array(CitationSchema),
|
|
8440
|
+
confidence: z39.number().min(0).max(1),
|
|
8441
|
+
needsMoreContext: z39.boolean().describe("True if evidence was insufficient to answer fully")
|
|
8442
|
+
});
|
|
8443
|
+
var VerifyResultSchema = z39.object({
|
|
8444
|
+
approved: z39.boolean().describe("Whether all sub-answers are adequately grounded"),
|
|
8445
|
+
issues: z39.array(z39.string()).describe("Specific grounding or consistency issues found"),
|
|
8446
|
+
retrySubQuestions: z39.array(z39.string()).optional().describe("Sub-questions that need additional retrieval or re-reasoning")
|
|
8447
|
+
});
|
|
8448
|
+
var QueryResultSchema = z39.object({
|
|
8449
|
+
answer: z39.string(),
|
|
8450
|
+
citations: z39.array(CitationSchema),
|
|
7895
8451
|
intent: QueryIntentSchema,
|
|
7896
|
-
confidence:
|
|
7897
|
-
followUp:
|
|
8452
|
+
confidence: z39.number().min(0).max(1),
|
|
8453
|
+
followUp: z39.string().optional().describe("Suggested follow-up question if applicable")
|
|
7898
8454
|
});
|
|
7899
8455
|
|
|
7900
8456
|
// src/query/retriever.ts
|
|
@@ -8899,6 +9455,7 @@ export {
|
|
|
8899
9455
|
CoverageSchema,
|
|
8900
9456
|
CoverageTriggerSchema,
|
|
8901
9457
|
CoverageValueTypeSchema,
|
|
9458
|
+
CoveredReasonSchema,
|
|
8902
9459
|
CrimeDeclarationsSchema,
|
|
8903
9460
|
CyberDeclarationsSchema,
|
|
8904
9461
|
DEDUCTIBLE_TYPES,
|
|
@@ -8911,6 +9468,7 @@ export {
|
|
|
8911
9468
|
DeductibleScheduleSchema,
|
|
8912
9469
|
DeductibleTypeSchema,
|
|
8913
9470
|
DefenseCostTreatmentSchema,
|
|
9471
|
+
DefinitionSchema,
|
|
8914
9472
|
DocumentTypeSchema,
|
|
8915
9473
|
DriverRecordSchema,
|
|
8916
9474
|
DwellingDetailsSchema,
|