@claritylabs/cl-sdk 3.0.32 → 3.1.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 +2 -2
- package/dist/application.d.mts +2 -0
- package/dist/application.d.ts +2 -0
- package/dist/application.js +2351 -0
- package/dist/application.js.map +1 -0
- package/dist/application.mjs +2283 -0
- package/dist/application.mjs.map +1 -0
- package/dist/index-D23NUbxr.d.mts +28983 -0
- package/dist/index-D23NUbxr.d.ts +28983 -0
- package/dist/index.d.mts +2169 -29743
- package/dist/index.d.ts +2169 -29743
- package/dist/index.js +657 -22
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +634 -19
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -1
package/dist/index.mjs
CHANGED
|
@@ -2981,6 +2981,14 @@ function valueFromNode(node, value, confidence = "medium") {
|
|
|
2981
2981
|
sourceSpanIds: node.sourceSpanIds
|
|
2982
2982
|
};
|
|
2983
2983
|
}
|
|
2984
|
+
function valueFromNodes(nodes, value, confidence = "medium", normalizedValue) {
|
|
2985
|
+
return {
|
|
2986
|
+
value,
|
|
2987
|
+
...normalizedValue ? { normalizedValue } : {},
|
|
2988
|
+
confidence,
|
|
2989
|
+
...sourceIds(nodes)
|
|
2990
|
+
};
|
|
2991
|
+
}
|
|
2984
2992
|
function firstMatch(nodes, patterns) {
|
|
2985
2993
|
for (const node of nodes) {
|
|
2986
2994
|
const text = nodeText(node);
|
|
@@ -3057,8 +3065,65 @@ function cleanNamedInsured(value) {
|
|
|
3057
3065
|
}
|
|
3058
3066
|
return clean;
|
|
3059
3067
|
}
|
|
3068
|
+
var PARTY_LABEL_PATTERNS = {
|
|
3069
|
+
namedInsured: /^(?:item\s*\d+[.)]?\s*)?(?:named insured(?:\s+and\s+address)?|insured name)$/i,
|
|
3070
|
+
insurer: /^(?:carrier|insurer|security)$/i,
|
|
3071
|
+
broker: /^(?:broker(?:\s+of\s+record)?|producer|agent)$/i
|
|
3072
|
+
};
|
|
3073
|
+
function partyLabelKind(value) {
|
|
3074
|
+
const clean = cleanValue(value.replace(/^\s*column\s+\d+\s*:\s*/i, ""));
|
|
3075
|
+
if (!clean) return void 0;
|
|
3076
|
+
if (PARTY_LABEL_PATTERNS.namedInsured.test(clean)) return "namedInsured";
|
|
3077
|
+
if (PARTY_LABEL_PATTERNS.insurer.test(clean)) return "insurer";
|
|
3078
|
+
if (PARTY_LABEL_PATTERNS.broker.test(clean)) return "broker";
|
|
3079
|
+
return void 0;
|
|
3080
|
+
}
|
|
3081
|
+
function isRejectedPartyValue(value) {
|
|
3082
|
+
const clean = normalizeWhitespace3(value);
|
|
3083
|
+
return /^(?:and address|of record|insurer|carrier|security|broker|producer|agent|the|a|an|is|are|was|were|agrees?|means?|includes?|shall|will)\b/i.test(clean);
|
|
3084
|
+
}
|
|
3085
|
+
function identityWithoutAddress(value) {
|
|
3086
|
+
const clean = cleanValue(value.replace(/\b(?:phone|tel|telephone|email|e-mail)\b.*$/i, "").replace(/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b.*$/i, ""));
|
|
3087
|
+
if (!clean) return void 0;
|
|
3088
|
+
const beforeStreet = clean.match(/^(.+?)\s+\d{1,6}\s+[A-Za-z0-9.'-]+(?:\s+[A-Za-z0-9.'-]+){0,5}\s+(?:street|st\.?|avenue|ave\.?|road|rd\.?|drive|dr\.?|lane|ln\.?|boulevard|blvd\.?|suite|ste\.?|floor|fl\.?|way|court|ct\.?)\b/i)?.[1];
|
|
3089
|
+
const beforeCityState = clean.match(/^(.+?)\s+[A-Z][A-Za-z.'-]+(?:\s+[A-Z][A-Za-z.'-]+)*,\s*[A-Z]{2}\s+\d{5}(?:-\d{4})?\b/)?.[1];
|
|
3090
|
+
return cleanValue(beforeStreet ?? beforeCityState ?? clean);
|
|
3091
|
+
}
|
|
3092
|
+
function cleanPartyIdentity(value, clean) {
|
|
3093
|
+
const raw = cleanValue(value);
|
|
3094
|
+
if (!raw || isRejectedPartyValue(raw)) return void 0;
|
|
3095
|
+
const identity = identityWithoutAddress(raw);
|
|
3096
|
+
const cleaned = identity ? clean(identity) : void 0;
|
|
3097
|
+
if (!cleaned || isRejectedPartyValue(cleaned)) return void 0;
|
|
3098
|
+
return {
|
|
3099
|
+
value: cleaned,
|
|
3100
|
+
...cleaned !== raw ? { normalizedValue: cleaned } : {}
|
|
3101
|
+
};
|
|
3102
|
+
}
|
|
3103
|
+
function partyFromTableRows(nodes, wanted, clean) {
|
|
3104
|
+
const children = childMap(nodes);
|
|
3105
|
+
for (const row of compactFactNodes(nodes).filter((node) => node.kind === "table_row")) {
|
|
3106
|
+
const cells = cellRows(row, children);
|
|
3107
|
+
for (const [index, cell] of cells.entries()) {
|
|
3108
|
+
const labelKind = partyLabelKind(cell.value) ?? partyLabelKind(cell.label);
|
|
3109
|
+
if (labelKind !== wanted) continue;
|
|
3110
|
+
const valueCell = cells.slice(index + 1).find((candidate) => !partyLabelKind(candidate.value) && !partyLabelKind(candidate.label));
|
|
3111
|
+
if (!valueCell) continue;
|
|
3112
|
+
const cleaned = cleanPartyIdentity(valueCell.value, clean);
|
|
3113
|
+
if (cleaned) return valueFromNodes([row, valueCell.node], cleaned.value, "high", cleaned.normalizedValue);
|
|
3114
|
+
}
|
|
3115
|
+
const parts = normalizeWhitespace3(row.textExcerpt ?? row.description ?? nodeText(row)).split(/\s+\|\s+|\t/).map(cleanValue).filter((part) => Boolean(part));
|
|
3116
|
+
for (const [index, part] of parts.entries()) {
|
|
3117
|
+
const labelKind = partyLabelKind(part);
|
|
3118
|
+
if (labelKind !== wanted) continue;
|
|
3119
|
+
const cleaned = cleanPartyIdentity(parts[index + 1] ?? "", clean);
|
|
3120
|
+
if (cleaned) return valueFromNodes([row], cleaned.value, "high", cleaned.normalizedValue);
|
|
3121
|
+
}
|
|
3122
|
+
}
|
|
3123
|
+
return void 0;
|
|
3124
|
+
}
|
|
3060
3125
|
function namedInsuredFromNodes(nodes) {
|
|
3061
|
-
return firstCleanMatch(nodes, [
|
|
3126
|
+
return partyFromTableRows(nodes, "namedInsured", cleanNamedInsured) ?? firstCleanMatch(nodes, [
|
|
3062
3127
|
/\b(?:named insured|insured name)\s*:?\s*(.+?)(?=\s+(?:insurance amount|benefit amount|policy number|policy date|owner|beneficiary|premium|coverage|risk classification|date this)\b|[|;\n]|$)/i,
|
|
3063
3128
|
/\b(?:insured persons?|insured person)\s*:\s*(.+?)(?=\s+(?:insurance amount|benefit amount|policy number|policy date|owner|beneficiary|premium|coverage|risk classification|date this)\b|[|;\n]|$)/i,
|
|
3064
3129
|
/\b(?:applicant|policyholder)\s*:?\s*(.+?)(?=\s+(?:coverage|policy number|insurer|carrier|premium|effective|expiration)\b|[|;\n]|$)/i
|
|
@@ -3067,12 +3132,19 @@ function namedInsuredFromNodes(nodes) {
|
|
|
3067
3132
|
function cleanInsurer(value) {
|
|
3068
3133
|
const clean = cleanValue(value);
|
|
3069
3134
|
if (!clean || clean.length > 140) return void 0;
|
|
3070
|
-
if (/^(mean|means|we|us|our)\b/i.test(clean)) return void 0;
|
|
3135
|
+
if (/^(mean|means|we|us|our|the|a|an|agrees?|shall|will)\b/i.test(clean)) return void 0;
|
|
3071
3136
|
if (/\b(table of contents|policy wording|provided solely|convenience)\b/i.test(clean)) return void 0;
|
|
3072
3137
|
const known = clean.match(/\b(Sun Life Assurance Company of Canada|Manulife|The Manufacturers Life Insurance Company)\b/i)?.[1];
|
|
3073
3138
|
return known ?? clean;
|
|
3074
3139
|
}
|
|
3075
3140
|
function insurerFromNodes(nodes) {
|
|
3141
|
+
const tableValue = partyFromTableRows(nodes, "insurer", cleanInsurer);
|
|
3142
|
+
if (tableValue) return tableValue;
|
|
3143
|
+
for (const node of compactFactNodes(nodes)) {
|
|
3144
|
+
const text = nodeText(node);
|
|
3145
|
+
const value = cleanInsurer(text.match(/\b([A-Z][A-Za-z&.,' -]{2,120}?(?:Insurance|Assurance|Indemnity|Casualty|Underwriting|Mutual|Risk|Reinsurance)\s+Company(?:\s+of\s+[A-Z][A-Za-z .'-]+)?)\s*\(\s*the\s+["']?Insurer["']?\s*\)/i)?.[1] ?? "");
|
|
3146
|
+
if (value) return valueFromNode(node, value, "high");
|
|
3147
|
+
}
|
|
3076
3148
|
return firstCleanMatch(nodes, [
|
|
3077
3149
|
/\bunderwritten by\s+([^|;\n.]{3,160})/i,
|
|
3078
3150
|
/\b(?:insurer|carrier|company|security)\s*:?\s*([^|;\n]{3,120})/i,
|
|
@@ -3118,6 +3190,19 @@ function coverageNameFromRow(text) {
|
|
|
3118
3190
|
);
|
|
3119
3191
|
return cleanCoverageLabel(first);
|
|
3120
3192
|
}
|
|
3193
|
+
function isDeclarationLimitLabel(value) {
|
|
3194
|
+
const label = normalizeLabel(value);
|
|
3195
|
+
return /\bitem\s*\d+[.)]?\s*limits?\s+of\s+liability\b/.test(label) || /^limits?\s+of\s+liability$/.test(label) || /^policy\s+limits?$/.test(label);
|
|
3196
|
+
}
|
|
3197
|
+
function declarationCoverageNameFromRow(row, children) {
|
|
3198
|
+
const cells = cellRows(row, children);
|
|
3199
|
+
const candidates = [
|
|
3200
|
+
row.title,
|
|
3201
|
+
...cells.flatMap((cell) => [cell.label, cell.value])
|
|
3202
|
+
];
|
|
3203
|
+
if (!candidates.some(isDeclarationLimitLabel)) return void 0;
|
|
3204
|
+
return candidates.some((candidate) => /\blimits?\s+of\s+liability\b/i.test(candidate ?? "")) ? "Limits of Liability" : "Policy Limits";
|
|
3205
|
+
}
|
|
3121
3206
|
function limitFromText(text) {
|
|
3122
3207
|
return moneyValue(
|
|
3123
3208
|
text.match(/\b(?:limit|liability|aggregate|occurrence|claim)\s*:?\s*(\$?\d[\d,]*(?:\.\d{2})?|\$?\d[\d,]*\s*(?:each|per|aggregate)[^|;]*)/i)?.[1] ?? text.match(/(\$\s?\d[\d,]*(?:\.\d{2})?)(?=.*\b(limit|aggregate|occurrence|claim|liability)\b)/i)?.[1]
|
|
@@ -3137,7 +3222,12 @@ function premiumFromNodes(nodes) {
|
|
|
3137
3222
|
return void 0;
|
|
3138
3223
|
}
|
|
3139
3224
|
function moneyAmount(value) {
|
|
3140
|
-
const
|
|
3225
|
+
const clean = cleanValue(value);
|
|
3226
|
+
if (!clean) return void 0;
|
|
3227
|
+
const currency = clean.match(/\$\s*([0-9][0-9,]*(?:\.\d+)?)/);
|
|
3228
|
+
const percent = clean.match(/\b([0-9][0-9,]*(?:\.\d+)?)\s*%/);
|
|
3229
|
+
const explicitNumeric = !/\bitem\s*\d+\b/i.test(clean) && /\b(?:limit|aggregate|claim|occurrence|loss|retention|deductible|sir|premium|amount)\b/i.test(clean) ? clean.match(/\b([0-9][0-9,]*(?:\.\d+)?)\b/) : void 0;
|
|
3230
|
+
const match = currency ?? percent ?? explicitNumeric;
|
|
3141
3231
|
if (!match) return void 0;
|
|
3142
3232
|
const amount = Number(match[1].replace(/,/g, ""));
|
|
3143
3233
|
return Number.isFinite(amount) ? amount : void 0;
|
|
@@ -3183,6 +3273,10 @@ function isValueCell(label, value) {
|
|
|
3183
3273
|
}
|
|
3184
3274
|
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);
|
|
3185
3275
|
}
|
|
3276
|
+
function isCoverageTermLabel(value) {
|
|
3277
|
+
const label = normalizeLabel(value);
|
|
3278
|
+
return /\b(limit|aggregate|retention|deductible|sir|retroactive|premium|amount|sub[-\s]?limit)\b/.test(label);
|
|
3279
|
+
}
|
|
3186
3280
|
function isNameCell(label, value) {
|
|
3187
3281
|
const normalizedLabel = normalizeLabel(label);
|
|
3188
3282
|
const normalizedValue = normalizeLabel(value);
|
|
@@ -3284,6 +3378,16 @@ function termFromCell(params) {
|
|
|
3284
3378
|
function termsFromRow(row, children) {
|
|
3285
3379
|
const cells = cellRows(row, children);
|
|
3286
3380
|
if (cells.length > 0) {
|
|
3381
|
+
const pairedTerms = [];
|
|
3382
|
+
for (const [index, cell] of cells.entries()) {
|
|
3383
|
+
const next = cells[index + 1];
|
|
3384
|
+
if (!next) continue;
|
|
3385
|
+
if (!isCoverageTermLabel(cell.value)) continue;
|
|
3386
|
+
if (isCoverageTermLabel(next.value) && moneyAmount(next.value) === void 0) continue;
|
|
3387
|
+
const term = termFromCell({ row, cell: next.node, label: cell.value, value: next.value });
|
|
3388
|
+
if (term) pairedTerms.push(term);
|
|
3389
|
+
}
|
|
3390
|
+
if (pairedTerms.length > 0) return pairedTerms;
|
|
3287
3391
|
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));
|
|
3288
3392
|
}
|
|
3289
3393
|
const text = normalizeWhitespace3(row.textExcerpt ?? row.description ?? nodeText(row));
|
|
@@ -3310,6 +3414,8 @@ function termsFromRow(row, children) {
|
|
|
3310
3414
|
return terms;
|
|
3311
3415
|
}
|
|
3312
3416
|
function nameFromRow(row, children) {
|
|
3417
|
+
const declarationName = declarationCoverageNameFromRow(row, children);
|
|
3418
|
+
if (declarationName) return declarationName;
|
|
3313
3419
|
const cells = cellRows(row, children);
|
|
3314
3420
|
const named = cells.find((cell) => isNameCell(cell.label, cell.value));
|
|
3315
3421
|
if (named) return cleanValue(named.value);
|
|
@@ -3487,7 +3593,7 @@ function buildParties(profile) {
|
|
|
3487
3593
|
if (profile.namedInsured) {
|
|
3488
3594
|
parties.push({
|
|
3489
3595
|
role: "named_insured",
|
|
3490
|
-
name: profile.namedInsured.value,
|
|
3596
|
+
name: profile.namedInsured.normalizedValue ?? profile.namedInsured.value,
|
|
3491
3597
|
sourceNodeIds: profile.namedInsured.sourceNodeIds,
|
|
3492
3598
|
sourceSpanIds: profile.namedInsured.sourceSpanIds
|
|
3493
3599
|
});
|
|
@@ -3495,7 +3601,7 @@ function buildParties(profile) {
|
|
|
3495
3601
|
if (profile.insurer) {
|
|
3496
3602
|
parties.push({
|
|
3497
3603
|
role: "insurer",
|
|
3498
|
-
name: profile.insurer.value,
|
|
3604
|
+
name: profile.insurer.normalizedValue ?? profile.insurer.value,
|
|
3499
3605
|
sourceNodeIds: profile.insurer.sourceNodeIds,
|
|
3500
3606
|
sourceSpanIds: profile.insurer.sourceSpanIds
|
|
3501
3607
|
});
|
|
@@ -3503,7 +3609,7 @@ function buildParties(profile) {
|
|
|
3503
3609
|
if (profile.broker) {
|
|
3504
3610
|
parties.push({
|
|
3505
3611
|
role: "broker",
|
|
3506
|
-
name: profile.broker.value,
|
|
3612
|
+
name: profile.broker.normalizedValue ?? profile.broker.value,
|
|
3507
3613
|
sourceNodeIds: profile.broker.sourceNodeIds,
|
|
3508
3614
|
sourceSpanIds: profile.broker.sourceSpanIds
|
|
3509
3615
|
});
|
|
@@ -10948,9 +11054,19 @@ function sourceTreeToOutline(sourceTree) {
|
|
|
10948
11054
|
});
|
|
10949
11055
|
return (byParent.get(root?.id) ?? []).map(visit);
|
|
10950
11056
|
}
|
|
11057
|
+
var NORMALIZED_COMPATIBILITY_FIELDS = /* @__PURE__ */ new Set([
|
|
11058
|
+
"policyNumber",
|
|
11059
|
+
"namedInsured",
|
|
11060
|
+
"insurer",
|
|
11061
|
+
"broker"
|
|
11062
|
+
]);
|
|
10951
11063
|
function valueOf(profile, key) {
|
|
10952
11064
|
const value = profile[key];
|
|
10953
|
-
|
|
11065
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || !("value" in value)) return void 0;
|
|
11066
|
+
if (NORMALIZED_COMPATIBILITY_FIELDS.has(key) && "normalizedValue" in value && typeof value.normalizedValue === "string" && value.normalizedValue.trim()) {
|
|
11067
|
+
return value.normalizedValue;
|
|
11068
|
+
}
|
|
11069
|
+
return String(value.value);
|
|
10954
11070
|
}
|
|
10955
11071
|
function materializeDocument(params) {
|
|
10956
11072
|
const profile = params.operationalProfile;
|
|
@@ -12548,6 +12664,55 @@ var ApplicationFieldSchema = z42.object({
|
|
|
12548
12664
|
acroFormName: z42.string().optional().describe("Native PDF AcroForm field name when available"),
|
|
12549
12665
|
validationStatus: z42.enum(["valid", "needs_review", "unsupported", "missing"]).optional()
|
|
12550
12666
|
});
|
|
12667
|
+
var ApplicationQuestionConditionSchema = z42.object({
|
|
12668
|
+
dependsOn: z42.string(),
|
|
12669
|
+
operator: z42.enum(["equals", "not_equals", "in", "not_in", "exists"]).optional(),
|
|
12670
|
+
value: z42.string().optional(),
|
|
12671
|
+
whenValue: z42.string().optional(),
|
|
12672
|
+
values: z42.array(z42.string()).optional()
|
|
12673
|
+
});
|
|
12674
|
+
var ApplicationRepeatSchema = z42.object({
|
|
12675
|
+
min: z42.number().int().nonnegative().optional(),
|
|
12676
|
+
max: z42.number().int().positive().optional(),
|
|
12677
|
+
label: z42.string().optional()
|
|
12678
|
+
});
|
|
12679
|
+
var ApplicationQuestionNodeSchema = z42.lazy(
|
|
12680
|
+
() => z42.object({
|
|
12681
|
+
id: z42.string(),
|
|
12682
|
+
nodeType: z42.enum(["group", "question", "repeat_group", "table"]),
|
|
12683
|
+
fieldId: z42.string().optional(),
|
|
12684
|
+
fieldPath: z42.string().optional(),
|
|
12685
|
+
parentId: z42.string().optional(),
|
|
12686
|
+
order: z42.number().int().nonnegative().optional(),
|
|
12687
|
+
label: z42.string(),
|
|
12688
|
+
section: z42.string().optional(),
|
|
12689
|
+
fieldType: FieldTypeSchema.optional(),
|
|
12690
|
+
required: z42.boolean().optional(),
|
|
12691
|
+
prompt: z42.string().optional(),
|
|
12692
|
+
options: z42.array(z42.string()).optional(),
|
|
12693
|
+
columns: z42.array(z42.string()).optional(),
|
|
12694
|
+
condition: ApplicationQuestionConditionSchema.optional(),
|
|
12695
|
+
repeat: ApplicationRepeatSchema.optional(),
|
|
12696
|
+
children: z42.array(ApplicationQuestionNodeSchema).optional()
|
|
12697
|
+
})
|
|
12698
|
+
);
|
|
12699
|
+
var ApplicationQuestionGraphSchema = z42.object({
|
|
12700
|
+
id: z42.string(),
|
|
12701
|
+
version: z42.string(),
|
|
12702
|
+
title: z42.string().optional(),
|
|
12703
|
+
applicationType: z42.string().nullable().optional(),
|
|
12704
|
+
source: z42.enum(["pdf", "manual", "imported", "generated"]).default("generated"),
|
|
12705
|
+
rootNodeIds: z42.array(z42.string()).optional(),
|
|
12706
|
+
nodes: z42.array(ApplicationQuestionNodeSchema)
|
|
12707
|
+
});
|
|
12708
|
+
var ApplicationTemplateSchema = z42.object({
|
|
12709
|
+
id: z42.string(),
|
|
12710
|
+
version: z42.string(),
|
|
12711
|
+
title: z42.string(),
|
|
12712
|
+
applicationType: z42.string().nullable().optional(),
|
|
12713
|
+
questionGraph: ApplicationQuestionGraphSchema,
|
|
12714
|
+
fields: z42.array(ApplicationFieldSchema).optional()
|
|
12715
|
+
});
|
|
12551
12716
|
var ApplicationClassifyResultSchema = z42.object({
|
|
12552
12717
|
isApplication: z42.boolean(),
|
|
12553
12718
|
confidence: z42.number().min(0).max(1),
|
|
@@ -12645,16 +12810,67 @@ var ApplicationQualityReportSchema = z42.object({
|
|
|
12645
12810
|
emailReview: ApplicationEmailReviewSchema.optional(),
|
|
12646
12811
|
qualityGateStatus: QualityGateStatusSchema
|
|
12647
12812
|
});
|
|
12813
|
+
var ApplicationContextProposalSchema = z42.object({
|
|
12814
|
+
id: z42.string(),
|
|
12815
|
+
fieldId: z42.string().optional(),
|
|
12816
|
+
key: z42.string(),
|
|
12817
|
+
value: z42.string(),
|
|
12818
|
+
category: z42.string(),
|
|
12819
|
+
source: z42.enum(["application", "user", "lookup", "policy", "email", "chat", "imessage", "mcp"]),
|
|
12820
|
+
confidence: z42.enum(["confirmed", "high", "medium", "low"]),
|
|
12821
|
+
sourceSpanIds: z42.array(z42.string()).optional(),
|
|
12822
|
+
userSourceSpanIds: z42.array(z42.string()).optional()
|
|
12823
|
+
});
|
|
12824
|
+
var ApplicationPacketAnswerSchema = z42.object({
|
|
12825
|
+
fieldId: z42.string(),
|
|
12826
|
+
label: z42.string(),
|
|
12827
|
+
section: z42.string(),
|
|
12828
|
+
value: z42.string(),
|
|
12829
|
+
source: z42.string(),
|
|
12830
|
+
confidence: z42.enum(["confirmed", "high", "medium", "low"]).optional(),
|
|
12831
|
+
sourceSpanIds: z42.array(z42.string()).optional(),
|
|
12832
|
+
userSourceSpanIds: z42.array(z42.string()).optional()
|
|
12833
|
+
});
|
|
12834
|
+
var ApplicationPacketSchema = z42.object({
|
|
12835
|
+
id: z42.string(),
|
|
12836
|
+
applicationId: z42.string(),
|
|
12837
|
+
title: z42.string(),
|
|
12838
|
+
status: z42.enum(["draft", "broker_ready", "submitted"]),
|
|
12839
|
+
answers: z42.array(ApplicationPacketAnswerSchema),
|
|
12840
|
+
missingFieldIds: z42.array(z42.string()),
|
|
12841
|
+
qualityReport: ApplicationQualityReportSchema,
|
|
12842
|
+
submissionNotes: z42.string().optional(),
|
|
12843
|
+
createdAt: z42.number()
|
|
12844
|
+
});
|
|
12648
12845
|
var ApplicationStateSchema = z42.object({
|
|
12649
12846
|
id: z42.string(),
|
|
12650
12847
|
pdfBase64: z42.string().optional().describe("Original PDF, omitted after extraction"),
|
|
12848
|
+
templateId: z42.string().optional(),
|
|
12849
|
+
templateVersion: z42.string().optional(),
|
|
12850
|
+
templateSnapshot: ApplicationTemplateSchema.optional(),
|
|
12651
12851
|
title: z42.string().optional(),
|
|
12652
12852
|
applicationType: z42.string().nullable().optional(),
|
|
12853
|
+
questionGraph: ApplicationQuestionGraphSchema.optional(),
|
|
12653
12854
|
fields: z42.array(ApplicationFieldSchema),
|
|
12654
12855
|
batches: z42.array(z42.array(z42.string())).optional(),
|
|
12655
12856
|
currentBatchIndex: z42.number().default(0),
|
|
12857
|
+
contextProposals: z42.array(ApplicationContextProposalSchema).optional(),
|
|
12858
|
+
packet: ApplicationPacketSchema.optional(),
|
|
12656
12859
|
qualityReport: ApplicationQualityReportSchema.optional(),
|
|
12657
|
-
status: z42.enum([
|
|
12860
|
+
status: z42.enum([
|
|
12861
|
+
"classifying",
|
|
12862
|
+
"extracting",
|
|
12863
|
+
"auto_filling",
|
|
12864
|
+
"batching",
|
|
12865
|
+
"collecting",
|
|
12866
|
+
"confirming",
|
|
12867
|
+
"mapping",
|
|
12868
|
+
"broker_review",
|
|
12869
|
+
"packet_ready",
|
|
12870
|
+
"submitted",
|
|
12871
|
+
"cancelled",
|
|
12872
|
+
"complete"
|
|
12873
|
+
]),
|
|
12658
12874
|
createdAt: z42.number(),
|
|
12659
12875
|
updatedAt: z42.number()
|
|
12660
12876
|
});
|
|
@@ -13353,7 +13569,7 @@ function planReplyActions(input) {
|
|
|
13353
13569
|
parseAnswers: input.intent.hasAnswers && hasCurrentFields,
|
|
13354
13570
|
runLookup: hasLookupRequests && input.hasDocumentStore,
|
|
13355
13571
|
answerQuestion: Boolean(input.intent.questionText) && (input.intent.primaryIntent === "question" || input.intent.primaryIntent === "mixed"),
|
|
13356
|
-
advanceBatch: hasCurrentFields && input.currentBatchFields.every((field) => !isUnfilled(field)),
|
|
13572
|
+
advanceBatch: hasCurrentFields && input.currentBatchFields.every((field) => !isUnfilled(field)) || !hasCurrentFields && nextBatchNeedsAnswers,
|
|
13357
13573
|
generateNextEmail: nextBatchNeedsAnswers
|
|
13358
13574
|
};
|
|
13359
13575
|
}
|
|
@@ -13392,12 +13608,287 @@ function isHighValueLookupField(field) {
|
|
|
13392
13608
|
].some((term) => text.includes(term));
|
|
13393
13609
|
}
|
|
13394
13610
|
|
|
13611
|
+
// src/application/question-graph.ts
|
|
13612
|
+
function buildQuestionGraphFromFields(fields, options) {
|
|
13613
|
+
const sectionNodes = /* @__PURE__ */ new Map();
|
|
13614
|
+
const nodes = [];
|
|
13615
|
+
for (const [index, field] of fields.entries()) {
|
|
13616
|
+
const sectionId = stableNodeId(["section", field.section]);
|
|
13617
|
+
let sectionNode = sectionNodes.get(sectionId);
|
|
13618
|
+
if (!sectionNode) {
|
|
13619
|
+
sectionNode = {
|
|
13620
|
+
id: sectionId,
|
|
13621
|
+
nodeType: "group",
|
|
13622
|
+
label: field.section,
|
|
13623
|
+
order: sectionNodes.size,
|
|
13624
|
+
children: []
|
|
13625
|
+
};
|
|
13626
|
+
sectionNodes.set(sectionId, sectionNode);
|
|
13627
|
+
nodes.push(sectionNode);
|
|
13628
|
+
}
|
|
13629
|
+
const child = {
|
|
13630
|
+
id: field.fieldAnchorId ?? stableNodeId(["field", field.section, field.id || field.label]),
|
|
13631
|
+
nodeType: field.fieldType === "table" ? "table" : "question",
|
|
13632
|
+
fieldId: field.id,
|
|
13633
|
+
fieldPath: `${field.section}.${field.id}`,
|
|
13634
|
+
parentId: sectionId,
|
|
13635
|
+
order: index,
|
|
13636
|
+
label: field.label,
|
|
13637
|
+
section: field.section,
|
|
13638
|
+
fieldType: field.fieldType,
|
|
13639
|
+
required: field.required,
|
|
13640
|
+
options: field.options,
|
|
13641
|
+
columns: field.columns,
|
|
13642
|
+
condition: field.condition ? {
|
|
13643
|
+
dependsOn: field.condition.dependsOn,
|
|
13644
|
+
operator: "equals",
|
|
13645
|
+
value: field.condition.whenValue,
|
|
13646
|
+
whenValue: field.condition.whenValue
|
|
13647
|
+
} : void 0
|
|
13648
|
+
};
|
|
13649
|
+
sectionNode.children = [...sectionNode.children ?? [], child];
|
|
13650
|
+
}
|
|
13651
|
+
return normalizeApplicationQuestionGraph({
|
|
13652
|
+
id: options.id,
|
|
13653
|
+
version: options.version ?? "v1",
|
|
13654
|
+
title: options.title,
|
|
13655
|
+
applicationType: options.applicationType,
|
|
13656
|
+
source: options.source ?? "generated",
|
|
13657
|
+
rootNodeIds: nodes.map((node) => node.id),
|
|
13658
|
+
nodes
|
|
13659
|
+
});
|
|
13660
|
+
}
|
|
13661
|
+
function normalizeApplicationQuestionGraph(graph) {
|
|
13662
|
+
const normalizedNodes = graph.nodes.map((node, index) => normalizeNode(node, void 0, index)).sort(compareNodes);
|
|
13663
|
+
return {
|
|
13664
|
+
...graph,
|
|
13665
|
+
rootNodeIds: graph.rootNodeIds?.length ? graph.rootNodeIds : normalizedNodes.map((node) => node.id),
|
|
13666
|
+
nodes: normalizedNodes
|
|
13667
|
+
};
|
|
13668
|
+
}
|
|
13669
|
+
function flattenQuestionGraph(graph) {
|
|
13670
|
+
const fields = [];
|
|
13671
|
+
for (const node of graph.nodes.sort(compareNodes)) {
|
|
13672
|
+
collectFields(node, fields);
|
|
13673
|
+
}
|
|
13674
|
+
return fields;
|
|
13675
|
+
}
|
|
13676
|
+
function getActiveApplicationFields(state) {
|
|
13677
|
+
const valueByFieldId = new Map(
|
|
13678
|
+
state.fields.filter((field) => field.value !== void 0 && field.value.trim() !== "").map((field) => [field.id, field.value ?? ""])
|
|
13679
|
+
);
|
|
13680
|
+
const graphConditions = /* @__PURE__ */ new Map();
|
|
13681
|
+
for (const node of state.questionGraph?.nodes ?? []) {
|
|
13682
|
+
collectNodeConditions(node, graphConditions);
|
|
13683
|
+
}
|
|
13684
|
+
return state.fields.filter((field) => {
|
|
13685
|
+
const graphCondition = graphConditions.get(field.id);
|
|
13686
|
+
return isConditionSatisfied(field.condition, valueByFieldId) && isQuestionConditionSatisfied(graphCondition, valueByFieldId);
|
|
13687
|
+
});
|
|
13688
|
+
}
|
|
13689
|
+
function getNextApplicationQuestions(state, limit = 8) {
|
|
13690
|
+
const activeUnfilled = getActiveApplicationFields(state).filter((field) => !field.value);
|
|
13691
|
+
if (activeUnfilled.length === 0) return [];
|
|
13692
|
+
const currentBatchIds = state.batches?.[state.currentBatchIndex] ?? [];
|
|
13693
|
+
const currentBatchFields = activeUnfilled.filter((field) => currentBatchIds.includes(field.id));
|
|
13694
|
+
return (currentBatchFields.length > 0 ? currentBatchFields : activeUnfilled).slice(0, limit);
|
|
13695
|
+
}
|
|
13696
|
+
function normalizeNode(node, parentId, index) {
|
|
13697
|
+
const children = node.children?.map((child, childIndex) => normalizeNode(child, node.id, childIndex));
|
|
13698
|
+
return {
|
|
13699
|
+
...node,
|
|
13700
|
+
parentId: node.parentId ?? parentId,
|
|
13701
|
+
order: node.order ?? index,
|
|
13702
|
+
fieldPath: node.fieldPath ?? (node.fieldId ? [node.section, node.fieldId].filter(Boolean).join(".") : void 0),
|
|
13703
|
+
children
|
|
13704
|
+
};
|
|
13705
|
+
}
|
|
13706
|
+
function collectFields(node, fields) {
|
|
13707
|
+
if ((node.nodeType === "question" || node.nodeType === "table") && node.fieldId) {
|
|
13708
|
+
fields.push({
|
|
13709
|
+
id: node.fieldId,
|
|
13710
|
+
label: node.label,
|
|
13711
|
+
section: node.section ?? "General",
|
|
13712
|
+
fieldType: node.fieldType ?? (node.nodeType === "table" ? "table" : "text"),
|
|
13713
|
+
required: node.required ?? false,
|
|
13714
|
+
options: node.options,
|
|
13715
|
+
columns: node.columns,
|
|
13716
|
+
condition: node.condition ? {
|
|
13717
|
+
dependsOn: node.condition.dependsOn,
|
|
13718
|
+
whenValue: node.condition.value ?? node.condition.whenValue ?? ""
|
|
13719
|
+
} : void 0,
|
|
13720
|
+
fieldAnchorId: node.id
|
|
13721
|
+
});
|
|
13722
|
+
}
|
|
13723
|
+
for (const child of node.children ?? []) {
|
|
13724
|
+
collectFields(child, fields);
|
|
13725
|
+
}
|
|
13726
|
+
}
|
|
13727
|
+
function collectNodeConditions(node, conditions) {
|
|
13728
|
+
if (node.fieldId && node.condition) {
|
|
13729
|
+
conditions.set(node.fieldId, node.condition);
|
|
13730
|
+
}
|
|
13731
|
+
for (const child of node.children ?? []) {
|
|
13732
|
+
collectNodeConditions(child, conditions);
|
|
13733
|
+
}
|
|
13734
|
+
}
|
|
13735
|
+
function isConditionSatisfied(condition, valueByFieldId) {
|
|
13736
|
+
if (!condition) return true;
|
|
13737
|
+
const current = valueByFieldId.get(condition.dependsOn);
|
|
13738
|
+
return normalizeValue(current) === normalizeValue(condition.whenValue);
|
|
13739
|
+
}
|
|
13740
|
+
function isQuestionConditionSatisfied(condition, valueByFieldId) {
|
|
13741
|
+
if (!condition) return true;
|
|
13742
|
+
const current = valueByFieldId.get(condition.dependsOn);
|
|
13743
|
+
const expected = condition.value ?? condition.whenValue;
|
|
13744
|
+
const values = condition.values ?? (expected !== void 0 ? [expected] : []);
|
|
13745
|
+
switch (condition.operator) {
|
|
13746
|
+
case "exists":
|
|
13747
|
+
return current !== void 0 && current.trim() !== "";
|
|
13748
|
+
case "not_equals":
|
|
13749
|
+
return normalizeValue(current) !== normalizeValue(expected);
|
|
13750
|
+
case "in":
|
|
13751
|
+
return values.map(normalizeValue).includes(normalizeValue(current));
|
|
13752
|
+
case "not_in":
|
|
13753
|
+
return !values.map(normalizeValue).includes(normalizeValue(current));
|
|
13754
|
+
case "equals":
|
|
13755
|
+
default:
|
|
13756
|
+
return normalizeValue(current) === normalizeValue(expected);
|
|
13757
|
+
}
|
|
13758
|
+
}
|
|
13759
|
+
function compareNodes(a, b) {
|
|
13760
|
+
return (a.order ?? 0) - (b.order ?? 0) || a.id.localeCompare(b.id);
|
|
13761
|
+
}
|
|
13762
|
+
function normalizeValue(value) {
|
|
13763
|
+
return (value ?? "").trim().toLowerCase();
|
|
13764
|
+
}
|
|
13765
|
+
function stableNodeId(parts) {
|
|
13766
|
+
return parts.join(":").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "node";
|
|
13767
|
+
}
|
|
13768
|
+
|
|
13769
|
+
// src/application/intake.ts
|
|
13770
|
+
function extractQuestionGraphFromFields(fields, options) {
|
|
13771
|
+
return buildQuestionGraphFromFields(fields, options);
|
|
13772
|
+
}
|
|
13773
|
+
function createApplicationRun(params) {
|
|
13774
|
+
const now = params.now ?? Date.now();
|
|
13775
|
+
const graph = normalizeApplicationQuestionGraph(params.template.questionGraph);
|
|
13776
|
+
const fields = params.template.fields?.length ? params.template.fields : flattenQuestionGraph(graph);
|
|
13777
|
+
return {
|
|
13778
|
+
id: params.applicationId,
|
|
13779
|
+
templateId: params.template.id,
|
|
13780
|
+
templateVersion: params.template.version,
|
|
13781
|
+
templateSnapshot: params.template,
|
|
13782
|
+
title: params.template.title,
|
|
13783
|
+
applicationType: params.template.applicationType,
|
|
13784
|
+
questionGraph: graph,
|
|
13785
|
+
fields,
|
|
13786
|
+
currentBatchIndex: 0,
|
|
13787
|
+
status: "collecting",
|
|
13788
|
+
createdAt: now,
|
|
13789
|
+
updatedAt: now
|
|
13790
|
+
};
|
|
13791
|
+
}
|
|
13792
|
+
function planNextApplicationQuestions(state, limit) {
|
|
13793
|
+
const fields = getNextApplicationQuestions(state, limit);
|
|
13794
|
+
return {
|
|
13795
|
+
status: fields.length === 0 ? "complete" : "needs_answers",
|
|
13796
|
+
fieldIds: fields.map((field) => field.id),
|
|
13797
|
+
fields
|
|
13798
|
+
};
|
|
13799
|
+
}
|
|
13800
|
+
function applyApplicationAnswers(state, answers, now = Date.now()) {
|
|
13801
|
+
const answerByFieldId = new Map(answers.map((answer) => [answer.fieldId, answer]));
|
|
13802
|
+
const fields = state.fields.map((field) => {
|
|
13803
|
+
const answer = answerByFieldId.get(field.id);
|
|
13804
|
+
if (!answer) return field;
|
|
13805
|
+
return {
|
|
13806
|
+
...field,
|
|
13807
|
+
value: answer.value,
|
|
13808
|
+
source: answer.source ?? "user",
|
|
13809
|
+
confidence: answer.confidence ?? "confirmed",
|
|
13810
|
+
sourceSpanIds: answer.sourceSpanIds ?? field.sourceSpanIds,
|
|
13811
|
+
userSourceSpanIds: answer.userSourceSpanIds ?? field.userSourceSpanIds,
|
|
13812
|
+
validationStatus: "valid"
|
|
13813
|
+
};
|
|
13814
|
+
});
|
|
13815
|
+
const nextState = {
|
|
13816
|
+
...state,
|
|
13817
|
+
fields,
|
|
13818
|
+
updatedAt: now
|
|
13819
|
+
};
|
|
13820
|
+
const nextQuestions = planNextApplicationQuestions(nextState);
|
|
13821
|
+
return {
|
|
13822
|
+
...nextState,
|
|
13823
|
+
status: nextQuestions.status === "complete" ? "confirming" : nextState.status,
|
|
13824
|
+
qualityReport: buildApplicationQualityReport(nextState)
|
|
13825
|
+
};
|
|
13826
|
+
}
|
|
13827
|
+
function proposeContextWrites(state) {
|
|
13828
|
+
return getActiveApplicationFields(state).filter((field) => field.value && field.confidence && field.confidence !== "low").map((field) => ({
|
|
13829
|
+
id: `${state.id}:${field.id}:context`,
|
|
13830
|
+
fieldId: field.id,
|
|
13831
|
+
key: stableContextKey(field),
|
|
13832
|
+
value: field.value ?? "",
|
|
13833
|
+
category: field.section,
|
|
13834
|
+
source: field.source?.startsWith("lookup:") ? "lookup" : "application",
|
|
13835
|
+
confidence: field.confidence ?? "medium",
|
|
13836
|
+
sourceSpanIds: field.sourceSpanIds,
|
|
13837
|
+
userSourceSpanIds: field.userSourceSpanIds
|
|
13838
|
+
}));
|
|
13839
|
+
}
|
|
13840
|
+
function buildApplicationPacket(state, options = {}) {
|
|
13841
|
+
const qualityReport = buildApplicationQualityReport(state);
|
|
13842
|
+
const activeFields = getActiveApplicationFields(state);
|
|
13843
|
+
const answers = activeFields.filter((field) => field.value).map((field) => ({
|
|
13844
|
+
fieldId: field.id,
|
|
13845
|
+
label: field.label,
|
|
13846
|
+
section: field.section,
|
|
13847
|
+
value: field.value ?? "",
|
|
13848
|
+
source: field.source ?? "unknown",
|
|
13849
|
+
confidence: field.confidence,
|
|
13850
|
+
sourceSpanIds: field.sourceSpanIds,
|
|
13851
|
+
userSourceSpanIds: field.userSourceSpanIds
|
|
13852
|
+
}));
|
|
13853
|
+
const missingFieldIds = activeFields.filter((field) => field.required && !field.value).map((field) => field.id);
|
|
13854
|
+
return {
|
|
13855
|
+
id: `${state.id}:packet`,
|
|
13856
|
+
applicationId: state.id,
|
|
13857
|
+
title: state.title ?? state.applicationType ?? "Insurance Application",
|
|
13858
|
+
status: qualityReport.qualityGateStatus === "failed" || missingFieldIds.length > 0 ? "draft" : "broker_ready",
|
|
13859
|
+
answers,
|
|
13860
|
+
missingFieldIds,
|
|
13861
|
+
qualityReport,
|
|
13862
|
+
submissionNotes: options.submissionNotes,
|
|
13863
|
+
createdAt: options.now ?? Date.now()
|
|
13864
|
+
};
|
|
13865
|
+
}
|
|
13866
|
+
function validateApplicationPacket(packet) {
|
|
13867
|
+
const issues = [...packet.qualityReport.issues];
|
|
13868
|
+
if (packet.missingFieldIds.length > 0) {
|
|
13869
|
+
issues.push({
|
|
13870
|
+
code: "packet_missing_required_answers",
|
|
13871
|
+
severity: "blocking",
|
|
13872
|
+
message: "Packet still has required unanswered application fields."
|
|
13873
|
+
});
|
|
13874
|
+
}
|
|
13875
|
+
return {
|
|
13876
|
+
...packet.qualityReport,
|
|
13877
|
+
issues,
|
|
13878
|
+
qualityGateStatus: issues.some((issue) => issue.severity === "blocking") ? "failed" : packet.qualityReport.qualityGateStatus
|
|
13879
|
+
};
|
|
13880
|
+
}
|
|
13881
|
+
function stableContextKey(field) {
|
|
13882
|
+
return `${field.section}.${field.label}`.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
13883
|
+
}
|
|
13884
|
+
|
|
13395
13885
|
// src/application/coordinator.ts
|
|
13396
13886
|
function createApplicationPipeline(config) {
|
|
13397
13887
|
const {
|
|
13398
13888
|
generateText,
|
|
13399
13889
|
generateObject,
|
|
13400
13890
|
applicationStore,
|
|
13891
|
+
templateStore,
|
|
13401
13892
|
documentStore,
|
|
13402
13893
|
memoryStore,
|
|
13403
13894
|
backfillProvider,
|
|
@@ -13434,11 +13925,18 @@ function createApplicationPipeline(config) {
|
|
|
13434
13925
|
const applicationProviderOptions = input.sourceSpans?.length ? { ...providerOptions, sourceSpans: input.sourceSpans } : providerOptions;
|
|
13435
13926
|
const id = input.applicationId ?? `app-${Date.now()}`;
|
|
13436
13927
|
const now = Date.now();
|
|
13928
|
+
if (input.template) {
|
|
13929
|
+
await templateStore?.saveTemplate(input.template);
|
|
13930
|
+
}
|
|
13437
13931
|
let state = {
|
|
13438
13932
|
id,
|
|
13933
|
+
templateId: input.template?.id,
|
|
13934
|
+
templateVersion: input.template?.version,
|
|
13935
|
+
templateSnapshot: input.template,
|
|
13439
13936
|
pdfBase64: void 0,
|
|
13440
13937
|
title: void 0,
|
|
13441
13938
|
applicationType: null,
|
|
13939
|
+
questionGraph: input.questionGraph ?? input.template?.questionGraph,
|
|
13442
13940
|
fields: [],
|
|
13443
13941
|
qualityReport: void 0,
|
|
13444
13942
|
batches: void 0,
|
|
@@ -13498,6 +13996,12 @@ function createApplicationPipeline(config) {
|
|
|
13498
13996
|
return { state, tokenUsage: totalUsage, reviewReport: state.qualityReport };
|
|
13499
13997
|
}
|
|
13500
13998
|
state.fields = fields;
|
|
13999
|
+
state.questionGraph = input.questionGraph ?? input.template?.questionGraph ?? buildQuestionGraphFromFields(fields, {
|
|
14000
|
+
id: `${id}:graph`,
|
|
14001
|
+
title: classifyResult.applicationType ?? void 0,
|
|
14002
|
+
applicationType: classifyResult.applicationType,
|
|
14003
|
+
source: "pdf"
|
|
14004
|
+
});
|
|
13501
14005
|
state.title = classifyResult.applicationType ?? void 0;
|
|
13502
14006
|
state.status = "auto_filling";
|
|
13503
14007
|
state.updatedAt = Date.now();
|
|
@@ -13518,8 +14022,10 @@ function createApplicationPipeline(config) {
|
|
|
13518
14022
|
if (field && !field.value && pa.relevance > 0.8) {
|
|
13519
14023
|
field.value = pa.value;
|
|
13520
14024
|
field.source = `backfill: ${pa.source}`;
|
|
13521
|
-
field.confidence = "high";
|
|
13522
|
-
field.validationStatus = "needs_review";
|
|
14025
|
+
field.confidence = pa.confidence ?? "high";
|
|
14026
|
+
field.validationStatus = pa.sourceSpanIds?.length ? "valid" : "needs_review";
|
|
14027
|
+
field.sourceSpanIds = pa.sourceSpanIds;
|
|
14028
|
+
field.userSourceSpanIds = pa.userSourceSpanIds;
|
|
13523
14029
|
}
|
|
13524
14030
|
}
|
|
13525
14031
|
} catch (e) {
|
|
@@ -13569,7 +14075,18 @@ function createApplicationPipeline(config) {
|
|
|
13569
14075
|
try {
|
|
13570
14076
|
const searchPromises = workflowPlan.documentSearchFields.map(
|
|
13571
14077
|
(f) => limit(async () => {
|
|
13572
|
-
await memoryStore.search(f.label
|
|
14078
|
+
const chunks = await memoryStore.search(`${f.section} ${f.label}`, { limit: 3 });
|
|
14079
|
+
const match = selectMemoryBackfillMatch(f, chunks);
|
|
14080
|
+
if (match) {
|
|
14081
|
+
const field = state.fields.find((candidate) => candidate.id === f.id);
|
|
14082
|
+
if (field && !field.value) {
|
|
14083
|
+
field.value = match.value;
|
|
14084
|
+
field.source = match.source;
|
|
14085
|
+
field.confidence = match.confidence;
|
|
14086
|
+
field.validationStatus = match.sourceSpanIds.length > 0 ? "valid" : "needs_review";
|
|
14087
|
+
field.sourceSpanIds = match.sourceSpanIds.length > 0 ? match.sourceSpanIds : void 0;
|
|
14088
|
+
}
|
|
14089
|
+
}
|
|
13573
14090
|
})
|
|
13574
14091
|
);
|
|
13575
14092
|
await Promise.all(searchPromises);
|
|
@@ -13589,7 +14106,7 @@ function createApplicationPipeline(config) {
|
|
|
13589
14106
|
hasDocumentStore: false,
|
|
13590
14107
|
hasMemoryStore: false
|
|
13591
14108
|
});
|
|
13592
|
-
const unfilledFields =
|
|
14109
|
+
const unfilledFields = getActiveApplicationFields(state).filter((field) => !field.value);
|
|
13593
14110
|
if (workflowPlan.runBatching) {
|
|
13594
14111
|
onProgress?.(`Batching ${unfilledFields.length} remaining questions...`);
|
|
13595
14112
|
state.status = "batching";
|
|
@@ -13611,6 +14128,7 @@ function createApplicationPipeline(config) {
|
|
|
13611
14128
|
} else {
|
|
13612
14129
|
state.status = "confirming";
|
|
13613
14130
|
}
|
|
14131
|
+
state.contextProposals = proposeContextWrites(state);
|
|
13614
14132
|
state.qualityReport = buildApplicationQualityReport(state);
|
|
13615
14133
|
state.updatedAt = Date.now();
|
|
13616
14134
|
await applicationStore?.save(state);
|
|
@@ -13638,7 +14156,8 @@ function createApplicationPipeline(config) {
|
|
|
13638
14156
|
throw new Error(`Application ${applicationId} not found`);
|
|
13639
14157
|
}
|
|
13640
14158
|
const currentBatchFieldIds = state.batches?.[state.currentBatchIndex] ?? [];
|
|
13641
|
-
const
|
|
14159
|
+
const activeFields = getActiveApplicationFields(state);
|
|
14160
|
+
const currentBatchFields = activeFields.filter(
|
|
13642
14161
|
(f) => currentBatchFieldIds.includes(f.id)
|
|
13643
14162
|
);
|
|
13644
14163
|
onProgress?.("Classifying reply...");
|
|
@@ -13761,14 +14280,16 @@ Provide a brief, helpful explanation (2-3 sentences). End with "Just reply with
|
|
|
13761
14280
|
responseText = `I wasn't able to generate an explanation for your question. Could you rephrase it, or just provide the answer directly?`;
|
|
13762
14281
|
}
|
|
13763
14282
|
}
|
|
13764
|
-
const
|
|
14283
|
+
const activeCurrentBatchFieldIds = currentBatchFields.map((field) => field.id);
|
|
14284
|
+
const currentBatchComplete = activeCurrentBatchFieldIds.every(
|
|
13765
14285
|
(fid) => state.fields.find((f) => f.id === fid)?.value
|
|
13766
14286
|
);
|
|
13767
14287
|
let nextBatchIndex;
|
|
13768
14288
|
let nextBatchFields;
|
|
13769
14289
|
if (state.batches) {
|
|
13770
14290
|
for (let index = state.currentBatchIndex + 1; index < state.batches.length; index++) {
|
|
13771
|
-
const
|
|
14291
|
+
const activeCandidateFields = getActiveApplicationFields(state);
|
|
14292
|
+
const candidateFields = activeCandidateFields.filter((f) => state.batches[index].includes(f.id));
|
|
13772
14293
|
if (candidateFields.some((f) => !f.value)) {
|
|
13773
14294
|
nextBatchIndex = index;
|
|
13774
14295
|
nextBatchFields = candidateFields;
|
|
@@ -13824,7 +14345,8 @@ ${emailText}`;
|
|
|
13824
14345
|
}
|
|
13825
14346
|
}
|
|
13826
14347
|
state.updatedAt = Date.now();
|
|
13827
|
-
state.
|
|
14348
|
+
state.contextProposals = proposeContextWrites(state);
|
|
14349
|
+
state.qualityReport = buildApplicationQualityReport(state);
|
|
13828
14350
|
await applicationStore?.save(state);
|
|
13829
14351
|
if (shouldFailQualityGate(qualityGate, state.qualityReport.qualityGateStatus)) {
|
|
13830
14352
|
throw new Error("Application quality gate failed. See state.qualityReport for blocking issues.");
|
|
@@ -13844,7 +14366,7 @@ ${emailText}`;
|
|
|
13844
14366
|
if (!state) throw new Error(`Application ${applicationId} not found`);
|
|
13845
14367
|
if (!state.batches?.length) throw new Error("No batches available");
|
|
13846
14368
|
const batchFieldIds = state.batches[state.currentBatchIndex];
|
|
13847
|
-
const batchFields = state.
|
|
14369
|
+
const batchFields = getActiveApplicationFields(state).filter((f) => batchFieldIds.includes(f.id));
|
|
13848
14370
|
const filledCount = state.fields.filter((f) => f.value).length;
|
|
13849
14371
|
const { text, usage } = await generateBatchEmail(
|
|
13850
14372
|
batchFields,
|
|
@@ -13892,13 +14414,86 @@ ${fieldSummary}`,
|
|
|
13892
14414
|
trackUsage(usage);
|
|
13893
14415
|
return { text, tokenUsage: totalUsage };
|
|
13894
14416
|
}
|
|
14417
|
+
async function createApplicationRun2(input) {
|
|
14418
|
+
const state = createApplicationRun(input);
|
|
14419
|
+
await applicationStore?.save(state);
|
|
14420
|
+
return state;
|
|
14421
|
+
}
|
|
14422
|
+
async function planNextQuestions(applicationId, limit2) {
|
|
14423
|
+
const state = await applicationStore?.get(applicationId);
|
|
14424
|
+
if (!state) throw new Error(`Application ${applicationId} not found`);
|
|
14425
|
+
return planNextApplicationQuestions(state, limit2);
|
|
14426
|
+
}
|
|
14427
|
+
async function proposeContextWrites2(applicationId) {
|
|
14428
|
+
const state = await applicationStore?.get(applicationId);
|
|
14429
|
+
if (!state) throw new Error(`Application ${applicationId} not found`);
|
|
14430
|
+
const proposals = proposeContextWrites(state);
|
|
14431
|
+
await applicationStore?.save({
|
|
14432
|
+
...state,
|
|
14433
|
+
contextProposals: proposals,
|
|
14434
|
+
updatedAt: Date.now()
|
|
14435
|
+
});
|
|
14436
|
+
return { proposals };
|
|
14437
|
+
}
|
|
14438
|
+
async function buildApplicationPacket2(input) {
|
|
14439
|
+
const state = await applicationStore?.get(input.applicationId);
|
|
14440
|
+
if (!state) throw new Error(`Application ${input.applicationId} not found`);
|
|
14441
|
+
const packet = buildApplicationPacket(state, {
|
|
14442
|
+
submissionNotes: input.submissionNotes,
|
|
14443
|
+
now: input.now
|
|
14444
|
+
});
|
|
14445
|
+
const reviewReport = validateApplicationPacket(packet);
|
|
14446
|
+
await applicationStore?.save({
|
|
14447
|
+
...state,
|
|
14448
|
+
packet: { ...packet, qualityReport: reviewReport },
|
|
14449
|
+
status: reviewReport.qualityGateStatus === "failed" ? "broker_review" : "packet_ready",
|
|
14450
|
+
qualityReport: reviewReport,
|
|
14451
|
+
updatedAt: Date.now()
|
|
14452
|
+
});
|
|
14453
|
+
return { packet: { ...packet, qualityReport: reviewReport }, reviewReport };
|
|
14454
|
+
}
|
|
13895
14455
|
return {
|
|
13896
14456
|
processApplication,
|
|
13897
14457
|
processReply: processReply2,
|
|
13898
14458
|
generateCurrentBatchEmail,
|
|
13899
|
-
getConfirmationSummary
|
|
14459
|
+
getConfirmationSummary,
|
|
14460
|
+
createApplicationRun: createApplicationRun2,
|
|
14461
|
+
planNextQuestions,
|
|
14462
|
+
proposeContextWrites: proposeContextWrites2,
|
|
14463
|
+
buildApplicationPacket: buildApplicationPacket2
|
|
13900
14464
|
};
|
|
13901
14465
|
}
|
|
14466
|
+
function selectMemoryBackfillMatch(field, chunks) {
|
|
14467
|
+
for (const chunk of chunks) {
|
|
14468
|
+
const value = chunk.metadata.value ?? chunk.metadata.answer ?? chunk.metadata.fieldValue;
|
|
14469
|
+
if (!value) continue;
|
|
14470
|
+
const metadataFieldId = chunk.metadata.fieldId ?? chunk.metadata.applicationFieldId;
|
|
14471
|
+
const metadataLabel = chunk.metadata.fieldLabel?.toLowerCase();
|
|
14472
|
+
const labelMatches = metadataLabel === field.label.toLowerCase();
|
|
14473
|
+
if (metadataFieldId && metadataFieldId !== field.id && !labelMatches) continue;
|
|
14474
|
+
return {
|
|
14475
|
+
value,
|
|
14476
|
+
source: chunk.metadata.source ?? `memory: ${chunk.documentId}`,
|
|
14477
|
+
confidence: metadataFieldId === field.id || labelMatches ? "high" : "medium",
|
|
14478
|
+
sourceSpanIds: parseSourceSpanIds(chunk.metadata.sourceSpanIds)
|
|
14479
|
+
};
|
|
14480
|
+
}
|
|
14481
|
+
return null;
|
|
14482
|
+
}
|
|
14483
|
+
function parseSourceSpanIds(value) {
|
|
14484
|
+
if (!value) return [];
|
|
14485
|
+
const trimmed = value.trim();
|
|
14486
|
+
if (!trimmed) return [];
|
|
14487
|
+
if (trimmed.startsWith("[")) {
|
|
14488
|
+
try {
|
|
14489
|
+
const parsed = JSON.parse(trimmed);
|
|
14490
|
+
return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string") : [];
|
|
14491
|
+
} catch {
|
|
14492
|
+
return [];
|
|
14493
|
+
}
|
|
14494
|
+
}
|
|
14495
|
+
return trimmed.split(",").map((item) => item.trim()).filter(Boolean);
|
|
14496
|
+
}
|
|
13902
14497
|
|
|
13903
14498
|
// src/prompts/application/confirmation.ts
|
|
13904
14499
|
function buildConfirmationSummaryPrompt(fields, applicationTitle) {
|
|
@@ -15978,13 +16573,21 @@ export {
|
|
|
15978
16573
|
AgenticExecutionModeSchema,
|
|
15979
16574
|
AnswerParsingResultSchema,
|
|
15980
16575
|
ApplicationClassifyResultSchema,
|
|
16576
|
+
ApplicationContextProposalSchema,
|
|
15981
16577
|
ApplicationEmailReviewSchema,
|
|
15982
16578
|
ApplicationFieldSchema,
|
|
16579
|
+
ApplicationPacketAnswerSchema,
|
|
16580
|
+
ApplicationPacketSchema,
|
|
15983
16581
|
ApplicationQualityArtifactSchema,
|
|
15984
16582
|
ApplicationQualityIssueSchema,
|
|
15985
16583
|
ApplicationQualityReportSchema,
|
|
15986
16584
|
ApplicationQualityRoundSchema,
|
|
16585
|
+
ApplicationQuestionConditionSchema,
|
|
16586
|
+
ApplicationQuestionGraphSchema,
|
|
16587
|
+
ApplicationQuestionNodeSchema,
|
|
16588
|
+
ApplicationRepeatSchema,
|
|
15987
16589
|
ApplicationStateSchema,
|
|
16590
|
+
ApplicationTemplateSchema,
|
|
15988
16591
|
AttachmentInterpretationSchema,
|
|
15989
16592
|
AuditTypeSchema,
|
|
15990
16593
|
AutoFillMatchSchema,
|
|
@@ -16199,9 +16802,11 @@ export {
|
|
|
16199
16802
|
VerifyResultSchema,
|
|
16200
16803
|
WatercraftDeclarationsSchema,
|
|
16201
16804
|
WorkersCompDeclarationsSchema,
|
|
16805
|
+
applyApplicationAnswers,
|
|
16202
16806
|
buildAcroFormMappingPrompt,
|
|
16203
16807
|
buildAgentSystemPrompt,
|
|
16204
16808
|
buildAnswerParsingPrompt,
|
|
16809
|
+
buildApplicationPacket,
|
|
16205
16810
|
buildAutoFillPrompt,
|
|
16206
16811
|
buildBatchEmailGenerationPrompt,
|
|
16207
16812
|
buildClassifyMessagePrompt,
|
|
@@ -16228,6 +16833,7 @@ export {
|
|
|
16228
16833
|
buildPdfProviderOptions,
|
|
16229
16834
|
buildQueryClassifyPrompt,
|
|
16230
16835
|
buildQuestionBatchPrompt,
|
|
16836
|
+
buildQuestionGraphFromFields,
|
|
16231
16837
|
buildQuotesPoliciesPrompt,
|
|
16232
16838
|
buildReasonPrompt,
|
|
16233
16839
|
buildReplyIntentClassificationPrompt,
|
|
@@ -16243,6 +16849,7 @@ export {
|
|
|
16243
16849
|
collectPceEvidenceSources,
|
|
16244
16850
|
compareSourceEvidence,
|
|
16245
16851
|
createApplicationPipeline,
|
|
16852
|
+
createApplicationRun,
|
|
16246
16853
|
createExtractor,
|
|
16247
16854
|
createPceAgent,
|
|
16248
16855
|
createPipelineContext,
|
|
@@ -16250,12 +16857,16 @@ export {
|
|
|
16250
16857
|
evaluateCaseProposals,
|
|
16251
16858
|
evidenceContainsQuote,
|
|
16252
16859
|
extractPageRange,
|
|
16860
|
+
extractQuestionGraphFromFields,
|
|
16253
16861
|
fillAcroForm,
|
|
16862
|
+
flattenQuestionGraph,
|
|
16254
16863
|
generateNextMessage,
|
|
16255
16864
|
getAcroFormFields,
|
|
16865
|
+
getActiveApplicationFields,
|
|
16256
16866
|
getDoclingPageRangeText,
|
|
16257
16867
|
getExtractor,
|
|
16258
16868
|
getFileIdentifier,
|
|
16869
|
+
getNextApplicationQuestions,
|
|
16259
16870
|
getPdfPageCount,
|
|
16260
16871
|
getTemplate,
|
|
16261
16872
|
isDoclingExtractionInput,
|
|
@@ -16263,6 +16874,7 @@ export {
|
|
|
16263
16874
|
mergeOperationalProfile,
|
|
16264
16875
|
mergeQuestionAnswers,
|
|
16265
16876
|
mergeSourceSpans,
|
|
16877
|
+
normalizeApplicationQuestionGraph,
|
|
16266
16878
|
normalizeDoclingDocument,
|
|
16267
16879
|
normalizeDocumentSourceTreePaths,
|
|
16268
16880
|
normalizeForMatch,
|
|
@@ -16272,7 +16884,9 @@ export {
|
|
|
16272
16884
|
pLimit,
|
|
16273
16885
|
pdfInputToBase64,
|
|
16274
16886
|
pdfInputToBytes,
|
|
16887
|
+
planNextApplicationQuestions,
|
|
16275
16888
|
processReply,
|
|
16889
|
+
proposeContextWrites,
|
|
16276
16890
|
resolveModelBudget,
|
|
16277
16891
|
safeGenerateObject,
|
|
16278
16892
|
sanitizeNulls,
|
|
@@ -16285,6 +16899,7 @@ export {
|
|
|
16285
16899
|
stableStringify,
|
|
16286
16900
|
stripFences,
|
|
16287
16901
|
toStrictSchema,
|
|
16902
|
+
validateApplicationPacket,
|
|
16288
16903
|
validateEvidence,
|
|
16289
16904
|
validatePceItems,
|
|
16290
16905
|
validateQuotedEvidence,
|