@claritylabs/cl-sdk 0.14.2 → 0.15.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/dist/index.mjs CHANGED
@@ -2232,10 +2232,13 @@ function chunkDocument(doc) {
2232
2232
  };
2233
2233
  const chunks = [];
2234
2234
  const docId = doc.id;
2235
+ const policyTypesStr = doc.policyTypes?.length ? doc.policyTypes.join(",") : void 0;
2235
2236
  function stringMetadata(entries) {
2236
- return Object.fromEntries(
2237
+ const base = Object.fromEntries(
2237
2238
  Object.entries(entries).filter(([, value]) => value !== void 0 && value !== null && String(value).length > 0).map(([key, value]) => [key, String(value)])
2238
2239
  );
2240
+ if (policyTypesStr) base.policyTypes = policyTypesStr;
2241
+ return base;
2239
2242
  }
2240
2243
  chunks.push({
2241
2244
  id: `${docId}:carrier_info:0`,
@@ -2596,13 +2599,16 @@ ${exc.content}`.trim(),
2596
2599
  }
2597
2600
  }
2598
2601
  if (declLines.length > 0) {
2602
+ const declMeta = { documentType: doc.type };
2603
+ if (typeof decl.formType === "string") declMeta.formType = decl.formType;
2604
+ if (typeof decl.line === "string") declMeta.declarationLine = decl.line;
2599
2605
  chunks.push({
2600
2606
  id: `${docId}:declaration:0`,
2601
2607
  documentId: docId,
2602
2608
  type: "declaration",
2603
2609
  text: `Declarations
2604
2610
  ${declLines.join("\n")}`,
2605
- metadata: stringMetadata({ documentType: doc.type })
2611
+ metadata: stringMetadata(declMeta)
2606
2612
  });
2607
2613
  }
2608
2614
  }
@@ -4023,11 +4029,30 @@ COMMERCIAL LINES \u2014 match these values:
4023
4029
  - "property" \u2014 standalone property
4024
4030
 
4025
4031
  PERSONAL LINES \u2014 match these values:
4026
- - "homeowners_ho3" \u2014 HO-3, special form homeowners
4027
- - "homeowners_ho5" \u2014 HO-5, comprehensive form homeowners
4028
- - "renters_ho4" \u2014 HO-4, renters insurance
4029
- - "condo_ho6" \u2014 HO-6, condo unit-owners
4030
- - "dwelling_fire" \u2014 DP-1, DP-3, dwelling fire
4032
+
4033
+ HOMEOWNER FORM CLASSIFICATION \u2014 pay close attention to these distinctions:
4034
+ - "homeowners_ho3" \u2014 HO-3 Special Form. Standard homeowner policy for OWNER-OCCUPIED dwellings.
4035
+ Key indicators: Coverage A (Dwelling) present, open-peril dwelling coverage, named-peril personal property,
4036
+ references to "special form", "HO 00 03", or "HO-3". The insured OWNS the home.
4037
+ - "homeowners_ho5" \u2014 HO-5 Comprehensive Form. Premium homeowner policy for OWNER-OCCUPIED dwellings.
4038
+ Key indicators: Coverage A (Dwelling) present, BOTH dwelling AND personal property on open-peril basis,
4039
+ references to "comprehensive form", "HO 00 05", or "HO-5". Higher coverage than HO-3.
4040
+ - "renters_ho4" \u2014 HO-4 Contents Broad Form. Renters/tenants insurance \u2014 NO dwelling coverage.
4041
+ Key indicators: NO Coverage A (Dwelling), only Coverage C (Personal Property) and Coverage E/F (Liability/Medical),
4042
+ references to "contents broad form", "HO 00 04", "HO-4", "renters", "tenants". The insured RENTS, does not own.
4043
+ - "condo_ho6" \u2014 HO-6 Unit-Owners Form. Condo/co-op unit-owner insurance.
4044
+ Key indicators: Coverage A applies to interior walls/improvements only (not full structure),
4045
+ references to "unit-owners form", "HO 00 06", "HO-6", "condominium", "co-op unit". The building's
4046
+ master policy covers the structure; HO-6 covers the unit interior, personal property, and liability.
4047
+
4048
+ DISAMBIGUATION RULES for homeowner forms:
4049
+ 1. If the document has Coverage A (Dwelling) with full structure coverage \u2192 HO-3 or HO-5 (check if open-peril on personal property \u2192 HO-5, named-peril \u2192 HO-3)
4050
+ 2. If NO Coverage A / no dwelling coverage and the insured is a renter/tenant \u2192 renters_ho4
4051
+ 3. If Coverage A covers only unit interior/improvements and mentions condo/co-op \u2192 condo_ho6
4052
+ 4. Look for the actual form number (HO 00 03, HO 00 04, HO 00 05, HO 00 06) on the declarations page \u2014 this is the most reliable indicator
4053
+ 5. Do NOT default to homeowners_ho3 when uncertain \u2014 check for the distinguishing signals above
4054
+
4055
+ - "dwelling_fire" \u2014 DP-1, DP-3, dwelling fire (non-owner-occupied or investment property)
4031
4056
  - "mobile_home" \u2014 mobile home, manufactured home
4032
4057
  - "personal_auto" \u2014 personal auto, PAP
4033
4058
  - "personal_umbrella" \u2014 personal umbrella
@@ -4038,7 +4063,10 @@ PERSONAL LINES \u2014 match these values:
4038
4063
  - "watercraft" \u2014 watercraft, boat
4039
4064
  - "recreational_vehicle" \u2014 RV, recreational vehicle, ATV
4040
4065
  - "farm_ranch" \u2014 farm, ranch
4041
- - "pet" \u2014 pet insurance
4066
+ - "pet" \u2014 standalone pet insurance policy. Key indicators: named pet, species/breed, accident/illness coverage,
4067
+ wellness plans, per-incident or annual limits for veterinary costs. Do NOT confuse with pet liability endorsements
4068
+ on a homeowners policy \u2014 those are still homeowner policies (ho3/ho4/ho5/ho6), not "pet".
4069
+ Only classify as "pet" when the ENTIRE policy is dedicated to pet health/accident coverage.
4042
4070
  - "travel" \u2014 travel insurance
4043
4071
  - "identity_theft" \u2014 identity theft
4044
4072
  - "title" \u2014 title insurance
@@ -4894,6 +4922,338 @@ function getExtractor(name) {
4894
4922
  return EXTRACTORS[name];
4895
4923
  }
4896
4924
 
4925
+ // src/extraction/resolve-referential.ts
4926
+ import { z as z35 } from "zod";
4927
+
4928
+ // src/prompts/extractors/referential-lookup.ts
4929
+ import { z as z34 } from "zod";
4930
+ var ReferentialLookupSchema = z34.object({
4931
+ resolvedCoverages: z34.array(
4932
+ z34.object({
4933
+ coverageName: z34.string().describe("The coverage name that was referenced"),
4934
+ resolvedLimit: z34.string().optional().describe("The concrete limit value found, if any"),
4935
+ resolvedLimitValueType: CoverageValueTypeSchema.optional(),
4936
+ resolvedDeductible: z34.string().optional().describe("The concrete deductible value found, if any"),
4937
+ resolvedDeductibleValueType: CoverageValueTypeSchema.optional(),
4938
+ pageNumber: z34.number().optional().describe("Page where the resolved value was found"),
4939
+ originalContent: z34.string().optional().describe("Verbatim source text for the resolved value"),
4940
+ confidence: z34.enum(["high", "medium", "low"]).describe("Confidence in the resolution")
4941
+ })
4942
+ )
4943
+ });
4944
+ function buildReferentialLookupPrompt(coverages) {
4945
+ const coverageList = coverages.map((c, i) => {
4946
+ const parts = [` ${i + 1}. Coverage: "${c.name}" \u2014 Limit: "${c.limit}"`];
4947
+ if (c.deductible) {
4948
+ parts.push(` Deductible: "${c.deductible}"`);
4949
+ }
4950
+ if (c.sectionRef) {
4951
+ parts.push(` Referenced section: "${c.sectionRef}"`);
4952
+ }
4953
+ return parts.join("\n");
4954
+ }).join("\n");
4955
+ return `You are an expert insurance document analyst. You are looking at a specific section of an insurance document to resolve referential coverage limits.
4956
+
4957
+ The following coverages had referential limits or deductibles (e.g. "As stated in Policy", "As stated in Section 4 of Policy", "See Declarations") instead of concrete values:
4958
+
4959
+ ${coverageList}
4960
+
4961
+ Your task:
4962
+ - Find the concrete/actual limit and deductible values for each coverage listed above.
4963
+ - Search the declarations page, coverage schedules, and any referenced sections for the real numeric or defined values.
4964
+ - Only return values you can actually find in the document \u2014 do not guess or infer values that are not explicitly stated.
4965
+ - For each resolved coverage, include:
4966
+ - pageNumber: the page where the resolved value appears
4967
+ - originalContent: the verbatim text snippet containing the resolved value
4968
+ - confidence: "high" if the value is clearly and unambiguously stated, "medium" if it requires interpretation, "low" if uncertain
4969
+ - If a coverage cannot be resolved (no concrete value found), still include it with confidence "low" and omit the resolved fields.
4970
+ - Classify resolvedLimitValueType and resolvedDeductibleValueType as numeric, included, not_included, as_stated, waiting_period, referential, or other.
4971
+
4972
+ Return JSON only.`;
4973
+ }
4974
+
4975
+ // src/extraction/resolve-referential.ts
4976
+ function looksReferential(value) {
4977
+ if (typeof value !== "string") return false;
4978
+ const normalized = value.toLowerCase();
4979
+ return normalized.includes("shown in the declarations") || normalized.includes("shown in declarations") || normalized.includes("shown in the schedule") || normalized.includes("as stated") || normalized.includes("if applicable");
4980
+ }
4981
+ function parseReferenceTarget(text) {
4982
+ if (typeof text !== "string") return void 0;
4983
+ const normalized = text.trim();
4984
+ if (!normalized) return void 0;
4985
+ const sectionMatch = normalized.match(/\b(Section\s+\d+[A-Za-z]?)/i);
4986
+ if (sectionMatch) return sectionMatch[1];
4987
+ if (/declarations/i.test(normalized)) return "Declarations";
4988
+ const scheduleMatch = normalized.match(/\b(Schedule(?:\s+of\s+[A-Za-z ]+)?)/i);
4989
+ if (scheduleMatch) return scheduleMatch[1].trim();
4990
+ const asStatedMatch = normalized.match(/(?:as\s+stated\s+in|see|shown\s+in(?:\s+the)?)\s+(.+)/i);
4991
+ if (asStatedMatch) {
4992
+ let target = asStatedMatch[1].trim().replace(/\s+of\s+the\s+policy$/i, "").trim();
4993
+ target = target.replace(/\.+$/, "").trim();
4994
+ if (target) return target;
4995
+ }
4996
+ if (/if applicable/i.test(normalized)) return void 0;
4997
+ return void 0;
4998
+ }
4999
+ var PageLocationSchema = z35.object({
5000
+ startPage: z35.number(),
5001
+ endPage: z35.number()
5002
+ });
5003
+ async function findReferencedPages(params) {
5004
+ const {
5005
+ referenceTarget,
5006
+ sections,
5007
+ formInventory,
5008
+ pdfBase64,
5009
+ pageCount,
5010
+ generateObject,
5011
+ providerOptions,
5012
+ log
5013
+ } = params;
5014
+ const targetLower = referenceTarget.toLowerCase();
5015
+ for (const section of sections) {
5016
+ if (section.title && section.pageStart != null && section.title.toLowerCase().includes(targetLower)) {
5017
+ return {
5018
+ startPage: section.pageStart,
5019
+ endPage: section.pageEnd ?? section.pageStart
5020
+ };
5021
+ }
5022
+ }
5023
+ for (const form of formInventory) {
5024
+ const titleMatch = form.title && form.title.toLowerCase().includes(targetLower);
5025
+ const typeMatch = form.formType && form.formType.toLowerCase().includes(targetLower);
5026
+ if ((titleMatch || typeMatch) && form.pageStart != null) {
5027
+ return {
5028
+ startPage: form.pageStart,
5029
+ endPage: form.pageEnd ?? form.pageStart
5030
+ };
5031
+ }
5032
+ }
5033
+ try {
5034
+ const result = await safeGenerateObject(
5035
+ generateObject,
5036
+ {
5037
+ prompt: `You are analyzing an insurance document (${pageCount} pages total).
5038
+
5039
+ Find the pages that contain the section or area referenced as "${referenceTarget}".
5040
+
5041
+ Return the page range (1-indexed) where this section is located. If the section spans a single page, startPage and endPage should be the same.
5042
+
5043
+ If you cannot find the section, return startPage: 0 and endPage: 0.
5044
+
5045
+ Return JSON only.`,
5046
+ schema: PageLocationSchema,
5047
+ maxTokens: 256,
5048
+ providerOptions: { ...providerOptions, pdfBase64 }
5049
+ },
5050
+ {
5051
+ fallback: { startPage: 0, endPage: 0 },
5052
+ maxRetries: 1,
5053
+ log,
5054
+ onError: (err, attempt) => log?.(
5055
+ `Page location attempt ${attempt + 1} failed for "${referenceTarget}": ${err instanceof Error ? err.message : String(err)}`
5056
+ )
5057
+ }
5058
+ );
5059
+ if (result.object.startPage > 0 && result.object.endPage > 0) {
5060
+ return {
5061
+ startPage: result.object.startPage,
5062
+ endPage: result.object.endPage
5063
+ };
5064
+ }
5065
+ } catch (error) {
5066
+ await log?.(
5067
+ `Failed to locate pages for "${referenceTarget}": ${error instanceof Error ? error.message : String(error)}`
5068
+ );
5069
+ }
5070
+ return void 0;
5071
+ }
5072
+ async function resolveReferentialCoverages(params) {
5073
+ const {
5074
+ memory,
5075
+ pdfBase64,
5076
+ pageCount,
5077
+ generateObject,
5078
+ convertPdfToImages,
5079
+ concurrency = 2,
5080
+ providerOptions,
5081
+ log,
5082
+ onProgress
5083
+ } = params;
5084
+ const limit = pLimit(concurrency);
5085
+ let totalUsage = { inputTokens: 0, outputTokens: 0 };
5086
+ function trackUsage(usage) {
5087
+ if (usage) {
5088
+ totalUsage.inputTokens += usage.inputTokens;
5089
+ totalUsage.outputTokens += usage.outputTokens;
5090
+ }
5091
+ }
5092
+ const coverageData = memory.get("coverage_limits");
5093
+ const coverages = coverageData?.coverages ?? [];
5094
+ const referentialCoverages = coverages.filter((cov) => {
5095
+ const limitType = cov.limitValueType;
5096
+ const deductibleType = cov.deductibleValueType;
5097
+ return limitType === "referential" || limitType === "as_stated" || deductibleType === "referential" || deductibleType === "as_stated" || looksReferential(cov.limit) || looksReferential(cov.deductible);
5098
+ });
5099
+ const attempts = referentialCoverages.length;
5100
+ if (attempts === 0) {
5101
+ return {
5102
+ resolved: 0,
5103
+ unresolved: 0,
5104
+ attempts: 0,
5105
+ usage: totalUsage,
5106
+ details: []
5107
+ };
5108
+ }
5109
+ onProgress?.(
5110
+ `Found ${attempts} referential coverage(s) to resolve...`
5111
+ );
5112
+ const targetGroups = /* @__PURE__ */ new Map();
5113
+ for (let i = 0; i < referentialCoverages.length; i++) {
5114
+ const cov = referentialCoverages[i];
5115
+ const refString = (looksReferential(cov.limit) ? cov.limit : void 0) ?? (looksReferential(cov.deductible) ? cov.deductible : void 0) ?? cov.limit ?? "";
5116
+ const target = parseReferenceTarget(refString) ?? "unknown";
5117
+ const group = targetGroups.get(target) ?? [];
5118
+ group.push({ coverage: cov, index: i });
5119
+ targetGroups.set(target, group);
5120
+ }
5121
+ const sectionsData = memory.get("sections");
5122
+ const sections = sectionsData?.sections ?? [];
5123
+ const formInventoryData = memory.get("form_inventory");
5124
+ const formInventory = formInventoryData?.forms ?? [];
5125
+ const details = [];
5126
+ let resolved = 0;
5127
+ let unresolved = 0;
5128
+ const targetEntries = Array.from(targetGroups.entries());
5129
+ await Promise.all(
5130
+ targetEntries.map(
5131
+ ([target, group]) => limit(async () => {
5132
+ const pageRange = await findReferencedPages({
5133
+ referenceTarget: target,
5134
+ sections,
5135
+ formInventory,
5136
+ pdfBase64,
5137
+ pageCount,
5138
+ generateObject,
5139
+ providerOptions,
5140
+ log
5141
+ });
5142
+ if (!pageRange) {
5143
+ await log?.(
5144
+ `Could not locate pages for reference target "${target}"`
5145
+ );
5146
+ for (const { coverage } of group) {
5147
+ details.push({
5148
+ coverageName: String(coverage.name ?? "unknown"),
5149
+ referenceTarget: target === "unknown" ? void 0 : target,
5150
+ status: "pages_not_found"
5151
+ });
5152
+ unresolved++;
5153
+ }
5154
+ return;
5155
+ }
5156
+ onProgress?.(
5157
+ `Resolving "${target}" from pages ${pageRange.startPage}-${pageRange.endPage}...`
5158
+ );
5159
+ const promptCoverages = group.map(({ coverage }) => ({
5160
+ name: String(coverage.name ?? "unknown"),
5161
+ limit: String(coverage.limit ?? ""),
5162
+ deductible: coverage.deductible ? String(coverage.deductible) : void 0,
5163
+ sectionRef: coverage.sectionRef ? String(coverage.sectionRef) : void 0
5164
+ }));
5165
+ try {
5166
+ const result = await runExtractor({
5167
+ name: "referential_lookup",
5168
+ prompt: buildReferentialLookupPrompt(promptCoverages),
5169
+ schema: ReferentialLookupSchema,
5170
+ pdfBase64,
5171
+ startPage: pageRange.startPage,
5172
+ endPage: pageRange.endPage,
5173
+ generateObject,
5174
+ convertPdfToImages,
5175
+ maxTokens: 4096,
5176
+ providerOptions
5177
+ });
5178
+ trackUsage(result.usage);
5179
+ const resolvedMap = /* @__PURE__ */ new Map();
5180
+ for (const rc of result.data.resolvedCoverages) {
5181
+ resolvedMap.set(rc.coverageName.toLowerCase(), rc);
5182
+ }
5183
+ for (const { coverage } of group) {
5184
+ const covName = String(coverage.name ?? "unknown");
5185
+ const rc = resolvedMap.get(covName.toLowerCase());
5186
+ if (!rc) {
5187
+ details.push({
5188
+ coverageName: covName,
5189
+ referenceTarget: target === "unknown" ? void 0 : target,
5190
+ status: "unresolved"
5191
+ });
5192
+ unresolved++;
5193
+ continue;
5194
+ }
5195
+ const limitResolved = rc.resolvedLimit && rc.resolvedLimitValueType !== "referential" && rc.resolvedLimitValueType !== "as_stated" && !looksReferential(rc.resolvedLimit);
5196
+ const deductibleResolved = rc.resolvedDeductible && rc.resolvedDeductibleValueType !== "referential" && rc.resolvedDeductibleValueType !== "as_stated" && !looksReferential(rc.resolvedDeductible);
5197
+ if (limitResolved || deductibleResolved) {
5198
+ if (limitResolved) {
5199
+ coverage.limit = rc.resolvedLimit;
5200
+ coverage.limitValueType = rc.resolvedLimitValueType ?? "numeric";
5201
+ }
5202
+ if (deductibleResolved) {
5203
+ coverage.deductible = rc.resolvedDeductible;
5204
+ coverage.deductibleValueType = rc.resolvedDeductibleValueType ?? "numeric";
5205
+ }
5206
+ if (rc.pageNumber != null) {
5207
+ coverage.resolvedFromPage = rc.pageNumber;
5208
+ }
5209
+ if (rc.originalContent) {
5210
+ coverage.resolvedOriginalContent = rc.originalContent;
5211
+ }
5212
+ details.push({
5213
+ coverageName: covName,
5214
+ referenceTarget: target === "unknown" ? void 0 : target,
5215
+ resolvedLimit: limitResolved ? rc.resolvedLimit : void 0,
5216
+ resolvedDeductible: deductibleResolved ? rc.resolvedDeductible : void 0,
5217
+ status: "resolved"
5218
+ });
5219
+ resolved++;
5220
+ } else {
5221
+ details.push({
5222
+ coverageName: covName,
5223
+ referenceTarget: target === "unknown" ? void 0 : target,
5224
+ status: "unresolved"
5225
+ });
5226
+ unresolved++;
5227
+ }
5228
+ }
5229
+ } catch (error) {
5230
+ await log?.(
5231
+ `Referential lookup extraction failed for target "${target}": ${error instanceof Error ? error.message : String(error)}`
5232
+ );
5233
+ for (const { coverage } of group) {
5234
+ details.push({
5235
+ coverageName: String(coverage.name ?? "unknown"),
5236
+ referenceTarget: target === "unknown" ? void 0 : target,
5237
+ status: "unresolved"
5238
+ });
5239
+ unresolved++;
5240
+ }
5241
+ }
5242
+ })
5243
+ )
5244
+ );
5245
+ onProgress?.(
5246
+ `Referential resolution complete: ${resolved} resolved, ${unresolved} unresolved out of ${attempts} attempts.`
5247
+ );
5248
+ return {
5249
+ resolved,
5250
+ unresolved,
5251
+ attempts,
5252
+ usage: totalUsage,
5253
+ details
5254
+ };
5255
+ }
5256
+
4897
5257
  // src/core/quality.ts
4898
5258
  function evaluateQualityGate(params) {
4899
5259
  const { issues, hasRoundWarnings = false } = params;
@@ -4930,7 +5290,7 @@ function addFormEntry(inventory, formNumber, source, extra) {
4930
5290
  sources: [source]
4931
5291
  });
4932
5292
  }
4933
- function looksReferential(value) {
5293
+ function looksReferential2(value) {
4934
5294
  if (typeof value !== "string") return false;
4935
5295
  const normalized = value.toLowerCase();
4936
5296
  return normalized.includes("shown in the declarations") || normalized.includes("shown in declarations") || normalized.includes("shown in the schedule") || normalized.includes("as stated") || normalized.includes("if applicable");
@@ -5054,7 +5414,7 @@ function buildExtractionReviewReport(params) {
5054
5414
  itemName: typeof coverage.name === "string" ? coverage.name : void 0
5055
5415
  });
5056
5416
  }
5057
- if (looksReferential(coverage.limit) || looksReferential(coverage.deductible)) {
5417
+ if (looksReferential2(coverage.limit) || looksReferential2(coverage.deductible)) {
5058
5418
  deterministicIssues.push({
5059
5419
  code: "coverage_referential_value",
5060
5420
  severity: "warning",
@@ -5176,7 +5536,8 @@ function buildExtractionReviewReport(params) {
5176
5536
  }));
5177
5537
  const artifacts = [
5178
5538
  { kind: "form_inventory", label: "Form Inventory", itemCount: formInventory.length },
5179
- { kind: "page_map", label: "Page Map", itemCount: params.pageAssignments.length }
5539
+ { kind: "page_map", label: "Page Map", itemCount: params.pageAssignments.length },
5540
+ { 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 }
5180
5541
  ];
5181
5542
  const qualityGateStatus = evaluateQualityGate({
5182
5543
  issues: deterministicIssues,
@@ -5663,6 +6024,37 @@ function createExtractor(config) {
5663
6024
  memory: Object.fromEntries(memory)
5664
6025
  });
5665
6026
  }
6027
+ if (!pipelineCtx.isPhaseComplete("resolve_referential")) {
6028
+ onProgress?.("Resolving referential coverage limits...");
6029
+ try {
6030
+ const resolution = await resolveReferentialCoverages({
6031
+ memory,
6032
+ pdfBase64,
6033
+ pageCount,
6034
+ generateObject,
6035
+ convertPdfToImages,
6036
+ concurrency,
6037
+ providerOptions,
6038
+ log,
6039
+ onProgress
6040
+ });
6041
+ trackUsage(resolution.usage);
6042
+ if (resolution.attempts > 0) {
6043
+ await log?.(`Referential resolution: ${resolution.resolved}/${resolution.attempts} resolved, ${resolution.unresolved} unresolved`);
6044
+ }
6045
+ } catch (error) {
6046
+ await log?.(`Referential resolution failed, continuing: ${error instanceof Error ? error.message : String(error)}`);
6047
+ }
6048
+ await pipelineCtx.save("resolve_referential", {
6049
+ id,
6050
+ pageCount,
6051
+ classifyResult,
6052
+ formInventory,
6053
+ pageAssignments,
6054
+ plan,
6055
+ memory: Object.fromEntries(memory)
6056
+ });
6057
+ }
5666
6058
  let reviewRounds = resumed?.reviewReport?.reviewRoundRecords ?? [];
5667
6059
  let reviewReport = resumed?.reviewReport;
5668
6060
  if (!pipelineCtx.isPhaseComplete("review")) {
@@ -6038,8 +6430,8 @@ Respond with JSON only:
6038
6430
  }`;
6039
6431
 
6040
6432
  // src/schemas/application.ts
6041
- import { z as z34 } from "zod";
6042
- var FieldTypeSchema = z34.enum([
6433
+ import { z as z36 } from "zod";
6434
+ var FieldTypeSchema = z36.enum([
6043
6435
  "text",
6044
6436
  "numeric",
6045
6437
  "currency",
@@ -6048,131 +6440,131 @@ var FieldTypeSchema = z34.enum([
6048
6440
  "table",
6049
6441
  "declaration"
6050
6442
  ]);
6051
- var ApplicationFieldSchema = z34.object({
6052
- id: z34.string(),
6053
- label: z34.string(),
6054
- section: z34.string(),
6443
+ var ApplicationFieldSchema = z36.object({
6444
+ id: z36.string(),
6445
+ label: z36.string(),
6446
+ section: z36.string(),
6055
6447
  fieldType: FieldTypeSchema,
6056
- required: z34.boolean(),
6057
- options: z34.array(z34.string()).optional(),
6058
- columns: z34.array(z34.string()).optional(),
6059
- requiresExplanationIfYes: z34.boolean().optional(),
6060
- condition: z34.object({
6061
- dependsOn: z34.string(),
6062
- whenValue: z34.string()
6448
+ required: z36.boolean(),
6449
+ options: z36.array(z36.string()).optional(),
6450
+ columns: z36.array(z36.string()).optional(),
6451
+ requiresExplanationIfYes: z36.boolean().optional(),
6452
+ condition: z36.object({
6453
+ dependsOn: z36.string(),
6454
+ whenValue: z36.string()
6063
6455
  }).optional(),
6064
- value: z34.string().optional(),
6065
- source: z34.string().optional().describe("Where the value came from: auto-fill, user, lookup"),
6066
- confidence: z34.enum(["confirmed", "high", "medium", "low"]).optional()
6456
+ value: z36.string().optional(),
6457
+ source: z36.string().optional().describe("Where the value came from: auto-fill, user, lookup"),
6458
+ confidence: z36.enum(["confirmed", "high", "medium", "low"]).optional()
6067
6459
  });
6068
- var ApplicationClassifyResultSchema = z34.object({
6069
- isApplication: z34.boolean(),
6070
- confidence: z34.number().min(0).max(1),
6071
- applicationType: z34.string().nullable()
6460
+ var ApplicationClassifyResultSchema = z36.object({
6461
+ isApplication: z36.boolean(),
6462
+ confidence: z36.number().min(0).max(1),
6463
+ applicationType: z36.string().nullable()
6072
6464
  });
6073
- var FieldExtractionResultSchema = z34.object({
6074
- fields: z34.array(ApplicationFieldSchema)
6465
+ var FieldExtractionResultSchema = z36.object({
6466
+ fields: z36.array(ApplicationFieldSchema)
6075
6467
  });
6076
- var AutoFillMatchSchema = z34.object({
6077
- fieldId: z34.string(),
6078
- value: z34.string(),
6079
- confidence: z34.enum(["confirmed"]),
6080
- contextKey: z34.string()
6468
+ var AutoFillMatchSchema = z36.object({
6469
+ fieldId: z36.string(),
6470
+ value: z36.string(),
6471
+ confidence: z36.enum(["confirmed"]),
6472
+ contextKey: z36.string()
6081
6473
  });
6082
- var AutoFillResultSchema = z34.object({
6083
- matches: z34.array(AutoFillMatchSchema)
6474
+ var AutoFillResultSchema = z36.object({
6475
+ matches: z36.array(AutoFillMatchSchema)
6084
6476
  });
6085
- var QuestionBatchResultSchema = z34.object({
6086
- batches: z34.array(z34.array(z34.string()).describe("Array of field IDs in this batch"))
6477
+ var QuestionBatchResultSchema = z36.object({
6478
+ batches: z36.array(z36.array(z36.string()).describe("Array of field IDs in this batch"))
6087
6479
  });
6088
- var LookupRequestSchema = z34.object({
6089
- type: z34.string().describe("Type of lookup: 'records', 'website', 'policy'"),
6090
- description: z34.string(),
6091
- url: z34.string().optional(),
6092
- targetFieldIds: z34.array(z34.string())
6480
+ var LookupRequestSchema = z36.object({
6481
+ type: z36.string().describe("Type of lookup: 'records', 'website', 'policy'"),
6482
+ description: z36.string(),
6483
+ url: z36.string().optional(),
6484
+ targetFieldIds: z36.array(z36.string())
6093
6485
  });
6094
- var ReplyIntentSchema = z34.object({
6095
- primaryIntent: z34.enum(["answers_only", "question", "lookup_request", "mixed"]),
6096
- hasAnswers: z34.boolean(),
6097
- questionText: z34.string().optional(),
6098
- questionFieldIds: z34.array(z34.string()).optional(),
6099
- lookupRequests: z34.array(LookupRequestSchema).optional()
6486
+ var ReplyIntentSchema = z36.object({
6487
+ primaryIntent: z36.enum(["answers_only", "question", "lookup_request", "mixed"]),
6488
+ hasAnswers: z36.boolean(),
6489
+ questionText: z36.string().optional(),
6490
+ questionFieldIds: z36.array(z36.string()).optional(),
6491
+ lookupRequests: z36.array(LookupRequestSchema).optional()
6100
6492
  });
6101
- var ParsedAnswerSchema = z34.object({
6102
- fieldId: z34.string(),
6103
- value: z34.string(),
6104
- explanation: z34.string().optional()
6493
+ var ParsedAnswerSchema = z36.object({
6494
+ fieldId: z36.string(),
6495
+ value: z36.string(),
6496
+ explanation: z36.string().optional()
6105
6497
  });
6106
- var AnswerParsingResultSchema = z34.object({
6107
- answers: z34.array(ParsedAnswerSchema),
6108
- unanswered: z34.array(z34.string()).describe("Field IDs that were not answered")
6498
+ var AnswerParsingResultSchema = z36.object({
6499
+ answers: z36.array(ParsedAnswerSchema),
6500
+ unanswered: z36.array(z36.string()).describe("Field IDs that were not answered")
6109
6501
  });
6110
- var LookupFillSchema = z34.object({
6111
- fieldId: z34.string(),
6112
- value: z34.string(),
6113
- source: z34.string().describe("Specific citable reference, e.g. 'GL Policy #POL-12345 (Hartford)'")
6502
+ var LookupFillSchema = z36.object({
6503
+ fieldId: z36.string(),
6504
+ value: z36.string(),
6505
+ source: z36.string().describe("Specific citable reference, e.g. 'GL Policy #POL-12345 (Hartford)'")
6114
6506
  });
6115
- var LookupFillResultSchema = z34.object({
6116
- fills: z34.array(LookupFillSchema),
6117
- unfillable: z34.array(z34.string()),
6118
- explanation: z34.string().optional()
6507
+ var LookupFillResultSchema = z36.object({
6508
+ fills: z36.array(LookupFillSchema),
6509
+ unfillable: z36.array(z36.string()),
6510
+ explanation: z36.string().optional()
6119
6511
  });
6120
- var FlatPdfPlacementSchema = z34.object({
6121
- fieldId: z34.string(),
6122
- page: z34.number(),
6123
- x: z34.number().describe("Percentage from left edge (0-100)"),
6124
- y: z34.number().describe("Percentage from top edge (0-100)"),
6125
- text: z34.string(),
6126
- fontSize: z34.number().optional(),
6127
- isCheckmark: z34.boolean().optional()
6512
+ var FlatPdfPlacementSchema = z36.object({
6513
+ fieldId: z36.string(),
6514
+ page: z36.number(),
6515
+ x: z36.number().describe("Percentage from left edge (0-100)"),
6516
+ y: z36.number().describe("Percentage from top edge (0-100)"),
6517
+ text: z36.string(),
6518
+ fontSize: z36.number().optional(),
6519
+ isCheckmark: z36.boolean().optional()
6128
6520
  });
6129
- var AcroFormMappingSchema = z34.object({
6130
- fieldId: z34.string(),
6131
- acroFormName: z34.string(),
6132
- value: z34.string()
6521
+ var AcroFormMappingSchema = z36.object({
6522
+ fieldId: z36.string(),
6523
+ acroFormName: z36.string(),
6524
+ value: z36.string()
6133
6525
  });
6134
- var QualityGateStatusSchema = z34.enum(["passed", "warning", "failed"]);
6135
- var QualitySeveritySchema = z34.enum(["info", "warning", "blocking"]);
6136
- var ApplicationQualityIssueSchema = z34.object({
6137
- code: z34.string(),
6526
+ var QualityGateStatusSchema = z36.enum(["passed", "warning", "failed"]);
6527
+ var QualitySeveritySchema = z36.enum(["info", "warning", "blocking"]);
6528
+ var ApplicationQualityIssueSchema = z36.object({
6529
+ code: z36.string(),
6138
6530
  severity: QualitySeveritySchema,
6139
- message: z34.string(),
6140
- fieldId: z34.string().optional()
6531
+ message: z36.string(),
6532
+ fieldId: z36.string().optional()
6141
6533
  });
6142
- var ApplicationQualityRoundSchema = z34.object({
6143
- round: z34.number(),
6144
- kind: z34.string(),
6534
+ var ApplicationQualityRoundSchema = z36.object({
6535
+ round: z36.number(),
6536
+ kind: z36.string(),
6145
6537
  status: QualityGateStatusSchema,
6146
- summary: z34.string().optional()
6538
+ summary: z36.string().optional()
6147
6539
  });
6148
- var ApplicationQualityArtifactSchema = z34.object({
6149
- kind: z34.string(),
6150
- label: z34.string().optional(),
6151
- itemCount: z34.number().optional()
6540
+ var ApplicationQualityArtifactSchema = z36.object({
6541
+ kind: z36.string(),
6542
+ label: z36.string().optional(),
6543
+ itemCount: z36.number().optional()
6152
6544
  });
6153
- var ApplicationEmailReviewSchema = z34.object({
6154
- issues: z34.array(ApplicationQualityIssueSchema),
6545
+ var ApplicationEmailReviewSchema = z36.object({
6546
+ issues: z36.array(ApplicationQualityIssueSchema),
6155
6547
  qualityGateStatus: QualityGateStatusSchema
6156
6548
  });
6157
- var ApplicationQualityReportSchema = z34.object({
6158
- issues: z34.array(ApplicationQualityIssueSchema),
6159
- rounds: z34.array(ApplicationQualityRoundSchema).optional(),
6160
- artifacts: z34.array(ApplicationQualityArtifactSchema).optional(),
6549
+ var ApplicationQualityReportSchema = z36.object({
6550
+ issues: z36.array(ApplicationQualityIssueSchema),
6551
+ rounds: z36.array(ApplicationQualityRoundSchema).optional(),
6552
+ artifacts: z36.array(ApplicationQualityArtifactSchema).optional(),
6161
6553
  emailReview: ApplicationEmailReviewSchema.optional(),
6162
6554
  qualityGateStatus: QualityGateStatusSchema
6163
6555
  });
6164
- var ApplicationStateSchema = z34.object({
6165
- id: z34.string(),
6166
- pdfBase64: z34.string().optional().describe("Original PDF, omitted after extraction"),
6167
- title: z34.string().optional(),
6168
- applicationType: z34.string().nullable().optional(),
6169
- fields: z34.array(ApplicationFieldSchema),
6170
- batches: z34.array(z34.array(z34.string())).optional(),
6171
- currentBatchIndex: z34.number().default(0),
6556
+ var ApplicationStateSchema = z36.object({
6557
+ id: z36.string(),
6558
+ pdfBase64: z36.string().optional().describe("Original PDF, omitted after extraction"),
6559
+ title: z36.string().optional(),
6560
+ applicationType: z36.string().nullable().optional(),
6561
+ fields: z36.array(ApplicationFieldSchema),
6562
+ batches: z36.array(z36.array(z36.string())).optional(),
6563
+ currentBatchIndex: z36.number().default(0),
6172
6564
  qualityReport: ApplicationQualityReportSchema.optional(),
6173
- status: z34.enum(["classifying", "extracting", "auto_filling", "batching", "collecting", "confirming", "mapping", "complete"]),
6174
- createdAt: z34.number(),
6175
- updatedAt: z34.number()
6565
+ status: z36.enum(["classifying", "extracting", "auto_filling", "batching", "collecting", "confirming", "mapping", "complete"]),
6566
+ createdAt: z36.number(),
6567
+ updatedAt: z36.number()
6176
6568
  });
6177
6569
 
6178
6570
  // src/application/agents/classifier.ts
@@ -7309,90 +7701,91 @@ Respond with the final answer, deduplicated citations array, overall confidence
7309
7701
  }
7310
7702
 
7311
7703
  // src/schemas/query.ts
7312
- import { z as z35 } from "zod";
7313
- var QueryIntentSchema = z35.enum([
7704
+ import { z as z37 } from "zod";
7705
+ var QueryIntentSchema = z37.enum([
7314
7706
  "policy_question",
7315
7707
  "coverage_comparison",
7316
7708
  "document_search",
7317
7709
  "claims_inquiry",
7318
7710
  "general_knowledge"
7319
7711
  ]);
7320
- var QueryAttachmentKindSchema = z35.enum(["image", "pdf", "text"]);
7321
- var QueryAttachmentSchema = z35.object({
7322
- id: z35.string().optional().describe("Optional stable attachment ID from the caller"),
7712
+ var QueryAttachmentKindSchema = z37.enum(["image", "pdf", "text"]);
7713
+ var QueryAttachmentSchema = z37.object({
7714
+ id: z37.string().optional().describe("Optional stable attachment ID from the caller"),
7323
7715
  kind: QueryAttachmentKindSchema,
7324
- name: z35.string().optional().describe("Original filename or user-facing label"),
7325
- mimeType: z35.string().optional().describe("MIME type such as image/jpeg or application/pdf"),
7326
- base64: z35.string().optional().describe("Base64-encoded file content for image/pdf attachments"),
7327
- text: z35.string().optional().describe("Plain-text attachment content when available"),
7328
- description: z35.string().optional().describe("Caller-provided description of the attachment")
7716
+ name: z37.string().optional().describe("Original filename or user-facing label"),
7717
+ mimeType: z37.string().optional().describe("MIME type such as image/jpeg or application/pdf"),
7718
+ base64: z37.string().optional().describe("Base64-encoded file content for image/pdf attachments"),
7719
+ text: z37.string().optional().describe("Plain-text attachment content when available"),
7720
+ description: z37.string().optional().describe("Caller-provided description of the attachment")
7329
7721
  });
7330
- var SubQuestionSchema = z35.object({
7331
- question: z35.string().describe("Atomic sub-question to retrieve and answer independently"),
7722
+ var SubQuestionSchema = z37.object({
7723
+ question: z37.string().describe("Atomic sub-question to retrieve and answer independently"),
7332
7724
  intent: QueryIntentSchema,
7333
- chunkTypes: z35.array(z35.string()).optional().describe("Chunk types to filter retrieval (e.g. coverage, endorsement, declaration)"),
7334
- documentFilters: z35.object({
7335
- type: z35.enum(["policy", "quote"]).optional(),
7336
- carrier: z35.string().optional(),
7337
- insuredName: z35.string().optional(),
7338
- policyNumber: z35.string().optional(),
7339
- quoteNumber: z35.string().optional()
7725
+ chunkTypes: z37.array(z37.string()).optional().describe("Chunk types to filter retrieval (e.g. coverage, endorsement, declaration)"),
7726
+ documentFilters: z37.object({
7727
+ type: z37.enum(["policy", "quote"]).optional(),
7728
+ carrier: z37.string().optional(),
7729
+ insuredName: z37.string().optional(),
7730
+ policyNumber: z37.string().optional(),
7731
+ quoteNumber: z37.string().optional(),
7732
+ policyTypes: z37.array(PolicyTypeSchema).optional().describe("Filter by policy type (e.g. homeowners_ho3, renters_ho4, pet) to avoid mixing up similar policies")
7340
7733
  }).optional().describe("Structured filters to narrow document lookup")
7341
7734
  });
7342
- var QueryClassifyResultSchema = z35.object({
7735
+ var QueryClassifyResultSchema = z37.object({
7343
7736
  intent: QueryIntentSchema,
7344
- subQuestions: z35.array(SubQuestionSchema).min(1).describe("Decomposed atomic sub-questions"),
7345
- requiresDocumentLookup: z35.boolean().describe("Whether structured document lookup is needed"),
7346
- requiresChunkSearch: z35.boolean().describe("Whether semantic chunk search is needed"),
7347
- requiresConversationHistory: z35.boolean().describe("Whether conversation history is relevant")
7737
+ subQuestions: z37.array(SubQuestionSchema).min(1).describe("Decomposed atomic sub-questions"),
7738
+ requiresDocumentLookup: z37.boolean().describe("Whether structured document lookup is needed"),
7739
+ requiresChunkSearch: z37.boolean().describe("Whether semantic chunk search is needed"),
7740
+ requiresConversationHistory: z37.boolean().describe("Whether conversation history is relevant")
7348
7741
  });
7349
- var EvidenceItemSchema = z35.object({
7350
- source: z35.enum(["chunk", "document", "conversation", "attachment"]),
7351
- chunkId: z35.string().optional(),
7352
- documentId: z35.string().optional(),
7353
- turnId: z35.string().optional(),
7354
- attachmentId: z35.string().optional(),
7355
- text: z35.string().describe("Text excerpt from the source"),
7356
- relevance: z35.number().min(0).max(1),
7357
- metadata: z35.array(z35.object({ key: z35.string(), value: z35.string() })).optional()
7742
+ var EvidenceItemSchema = z37.object({
7743
+ source: z37.enum(["chunk", "document", "conversation", "attachment"]),
7744
+ chunkId: z37.string().optional(),
7745
+ documentId: z37.string().optional(),
7746
+ turnId: z37.string().optional(),
7747
+ attachmentId: z37.string().optional(),
7748
+ text: z37.string().describe("Text excerpt from the source"),
7749
+ relevance: z37.number().min(0).max(1),
7750
+ metadata: z37.array(z37.object({ key: z37.string(), value: z37.string() })).optional()
7358
7751
  });
7359
- var AttachmentInterpretationSchema = z35.object({
7360
- summary: z35.string().describe("Concise summary of what the attachment shows or contains"),
7361
- extractedFacts: z35.array(z35.string()).describe("Specific observable or document facts grounded in the attachment"),
7362
- recommendedFocus: z35.array(z35.string()).describe("Important details to incorporate when answering follow-up questions"),
7363
- confidence: z35.number().min(0).max(1)
7752
+ var AttachmentInterpretationSchema = z37.object({
7753
+ summary: z37.string().describe("Concise summary of what the attachment shows or contains"),
7754
+ extractedFacts: z37.array(z37.string()).describe("Specific observable or document facts grounded in the attachment"),
7755
+ recommendedFocus: z37.array(z37.string()).describe("Important details to incorporate when answering follow-up questions"),
7756
+ confidence: z37.number().min(0).max(1)
7364
7757
  });
7365
- var RetrievalResultSchema = z35.object({
7366
- subQuestion: z35.string(),
7367
- evidence: z35.array(EvidenceItemSchema)
7758
+ var RetrievalResultSchema = z37.object({
7759
+ subQuestion: z37.string(),
7760
+ evidence: z37.array(EvidenceItemSchema)
7368
7761
  });
7369
- var CitationSchema = z35.object({
7370
- index: z35.number().describe("Citation number [1], [2], etc."),
7371
- chunkId: z35.string().describe("Source chunk ID, e.g. doc-123:coverage:2"),
7372
- documentId: z35.string(),
7373
- documentType: z35.enum(["policy", "quote"]).optional(),
7374
- field: z35.string().optional().describe("Specific field path, e.g. coverages[0].deductible"),
7375
- quote: z35.string().describe("Exact text from source that supports the claim"),
7376
- relevance: z35.number().min(0).max(1)
7762
+ var CitationSchema = z37.object({
7763
+ index: z37.number().describe("Citation number [1], [2], etc."),
7764
+ chunkId: z37.string().describe("Source chunk ID, e.g. doc-123:coverage:2"),
7765
+ documentId: z37.string(),
7766
+ documentType: z37.enum(["policy", "quote"]).optional(),
7767
+ field: z37.string().optional().describe("Specific field path, e.g. coverages[0].deductible"),
7768
+ quote: z37.string().describe("Exact text from source that supports the claim"),
7769
+ relevance: z37.number().min(0).max(1)
7377
7770
  });
7378
- var SubAnswerSchema = z35.object({
7379
- subQuestion: z35.string(),
7380
- answer: z35.string(),
7381
- citations: z35.array(CitationSchema),
7382
- confidence: z35.number().min(0).max(1),
7383
- needsMoreContext: z35.boolean().describe("True if evidence was insufficient to answer fully")
7771
+ var SubAnswerSchema = z37.object({
7772
+ subQuestion: z37.string(),
7773
+ answer: z37.string(),
7774
+ citations: z37.array(CitationSchema),
7775
+ confidence: z37.number().min(0).max(1),
7776
+ needsMoreContext: z37.boolean().describe("True if evidence was insufficient to answer fully")
7384
7777
  });
7385
- var VerifyResultSchema = z35.object({
7386
- approved: z35.boolean().describe("Whether all sub-answers are adequately grounded"),
7387
- issues: z35.array(z35.string()).describe("Specific grounding or consistency issues found"),
7388
- retrySubQuestions: z35.array(z35.string()).optional().describe("Sub-questions that need additional retrieval or re-reasoning")
7778
+ var VerifyResultSchema = z37.object({
7779
+ approved: z37.boolean().describe("Whether all sub-answers are adequately grounded"),
7780
+ issues: z37.array(z37.string()).describe("Specific grounding or consistency issues found"),
7781
+ retrySubQuestions: z37.array(z37.string()).optional().describe("Sub-questions that need additional retrieval or re-reasoning")
7389
7782
  });
7390
- var QueryResultSchema = z35.object({
7391
- answer: z35.string(),
7392
- citations: z35.array(CitationSchema),
7783
+ var QueryResultSchema = z37.object({
7784
+ answer: z37.string(),
7785
+ citations: z37.array(CitationSchema),
7393
7786
  intent: QueryIntentSchema,
7394
- confidence: z35.number().min(0).max(1),
7395
- followUp: z35.string().optional().describe("Suggested follow-up question if applicable")
7787
+ confidence: z37.number().min(0).max(1),
7788
+ followUp: z37.string().optional().describe("Suggested follow-up question if applicable")
7396
7789
  });
7397
7790
 
7398
7791
  // src/query/retriever.ts