@claritylabs/cl-sdk 0.12.0 → 0.13.1

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.js CHANGED
@@ -40,6 +40,7 @@ __export(index_exports, {
40
40
  AuditTypeSchema: () => AuditTypeSchema,
41
41
  AutoFillMatchSchema: () => AutoFillMatchSchema,
42
42
  AutoFillResultSchema: () => AutoFillResultSchema,
43
+ AuxiliaryFactSchema: () => AuxiliaryFactSchema,
43
44
  BOAT_TYPES: () => BOAT_TYPES,
44
45
  BindingAuthoritySchema: () => BindingAuthoritySchema,
45
46
  BoatTypeSchema: () => BoatTypeSchema,
@@ -1471,6 +1472,12 @@ var PremiumLineSchema = import_zod16.z.object({
1471
1472
  line: import_zod16.z.string(),
1472
1473
  amount: import_zod16.z.string()
1473
1474
  });
1475
+ var AuxiliaryFactSchema = import_zod16.z.object({
1476
+ key: import_zod16.z.string(),
1477
+ value: import_zod16.z.string(),
1478
+ subject: import_zod16.z.string().optional(),
1479
+ context: import_zod16.z.string().optional()
1480
+ });
1474
1481
  var BaseDocumentFields = {
1475
1482
  id: import_zod16.z.string(),
1476
1483
  carrier: import_zod16.z.string(),
@@ -1536,7 +1543,8 @@ var BaseDocumentFields = {
1536
1543
  individualClaims: import_zod16.z.array(ClaimRecordSchema).optional(),
1537
1544
  experienceMod: ExperienceModSchema.optional(),
1538
1545
  cancellationNoticeDays: import_zod16.z.number().optional(),
1539
- nonrenewalNoticeDays: import_zod16.z.number().optional()
1546
+ nonrenewalNoticeDays: import_zod16.z.number().optional(),
1547
+ supplementaryFacts: import_zod16.z.array(AuxiliaryFactSchema).optional()
1540
1548
  };
1541
1549
  var PolicyDocumentSchema = import_zod16.z.object({
1542
1550
  ...BaseDocumentFields,
@@ -2199,6 +2207,7 @@ function assembleDocument(documentId, documentType, memory) {
2199
2207
  ...sanitizeNulls(coverages ?? {}),
2200
2208
  ...sanitizeNulls(premium ?? {}),
2201
2209
  ...sanitizeNulls(supplementary ?? {}),
2210
+ supplementaryFacts: supplementary?.auxiliaryFacts,
2202
2211
  endorsements: endorsements?.endorsements,
2203
2212
  exclusions: exclusions?.exclusions,
2204
2213
  conditions: conditions?.conditions,
@@ -2551,6 +2560,43 @@ Total Cost: ${doc.totalCost}` : ""}`,
2551
2560
  metadata: stringMetadata({ premium: doc.premium, documentType: doc.type })
2552
2561
  });
2553
2562
  }
2563
+ const supplementaryLines = [
2564
+ ...doc.claimsContacts?.map((contact) => `Claims Contact: ${[
2565
+ contact.name,
2566
+ contact.phone,
2567
+ contact.email,
2568
+ contact.hours
2569
+ ].filter(Boolean).join(" | ")}`) ?? [],
2570
+ ...doc.regulatoryContacts?.map((contact) => `Regulatory Contact: ${[
2571
+ contact.name,
2572
+ contact.phone,
2573
+ contact.email
2574
+ ].filter(Boolean).join(" | ")}`) ?? [],
2575
+ ...doc.thirdPartyAdministrators?.map((contact) => `TPA: ${[
2576
+ contact.name,
2577
+ contact.phone,
2578
+ contact.email
2579
+ ].filter(Boolean).join(" | ")}`) ?? [],
2580
+ ...doc.supplementaryFacts?.map((fact) => [
2581
+ fact.subject ? `Subject: ${fact.subject}` : null,
2582
+ `${fact.key}: ${fact.value}`,
2583
+ fact.context ? `Context: ${fact.context}` : null
2584
+ ].filter(Boolean).join(" | ")) ?? [],
2585
+ doc.cancellationNoticeDays != null ? `Cancellation Notice Days: ${doc.cancellationNoticeDays}` : null,
2586
+ doc.nonrenewalNoticeDays != null ? `Nonrenewal Notice Days: ${doc.nonrenewalNoticeDays}` : null
2587
+ ].filter((line) => Boolean(line));
2588
+ if (supplementaryLines.length > 0) {
2589
+ chunks.push({
2590
+ id: `${docId}:supplementary:0`,
2591
+ documentId: docId,
2592
+ type: "supplementary",
2593
+ text: supplementaryLines.join("\n"),
2594
+ metadata: stringMetadata({
2595
+ documentType: doc.type,
2596
+ supplementaryFactCount: doc.supplementaryFacts?.length
2597
+ })
2598
+ });
2599
+ }
2554
2600
  return chunks;
2555
2601
  }
2556
2602
 
@@ -2634,6 +2680,32 @@ function mergeArrayPayload(existing, incoming, arrayKey, keyFn) {
2634
2680
  merged[arrayKey] = mergeUniqueObjects(existingItems, incomingItems, keyFn);
2635
2681
  return merged;
2636
2682
  }
2683
+ function mergeSupplementary(existing, incoming) {
2684
+ const merged = mergeShallowPreferPresent(existing, incoming);
2685
+ const mergeContactArray = (arrayKey) => {
2686
+ const existingItems = Array.isArray(existing[arrayKey]) ? existing[arrayKey] : [];
2687
+ const incomingItems = Array.isArray(incoming[arrayKey]) ? incoming[arrayKey] : [];
2688
+ merged[arrayKey] = mergeUniqueObjects(existingItems, incomingItems, (item) => [
2689
+ String(item.name ?? "").toLowerCase(),
2690
+ String(item.phone ?? "").toLowerCase(),
2691
+ String(item.email ?? "").toLowerCase(),
2692
+ String(item.address ?? "").toLowerCase(),
2693
+ String(item.type ?? "").toLowerCase()
2694
+ ].join("|"));
2695
+ };
2696
+ mergeContactArray("regulatoryContacts");
2697
+ mergeContactArray("claimsContacts");
2698
+ mergeContactArray("thirdPartyAdministrators");
2699
+ const existingFacts = Array.isArray(existing.auxiliaryFacts) ? existing.auxiliaryFacts : [];
2700
+ const incomingFacts = Array.isArray(incoming.auxiliaryFacts) ? incoming.auxiliaryFacts : [];
2701
+ merged.auxiliaryFacts = mergeUniqueObjects(existingFacts, incomingFacts, (item) => [
2702
+ String(item.key ?? "").toLowerCase(),
2703
+ String(item.value ?? "").toLowerCase(),
2704
+ String(item.subject ?? "").toLowerCase(),
2705
+ String(item.context ?? "").toLowerCase()
2706
+ ].join("|"));
2707
+ return merged;
2708
+ }
2637
2709
  function mergeExtractorResult(extractorName, existing, incoming) {
2638
2710
  if (!existing) return incoming;
2639
2711
  if (!incoming) return existing;
@@ -2644,9 +2716,10 @@ function mergeExtractorResult(extractorName, existing, incoming) {
2644
2716
  case "carrier_info":
2645
2717
  case "named_insured":
2646
2718
  case "loss_history":
2647
- case "supplementary":
2648
2719
  case "premium_breakdown":
2649
2720
  return mergeShallowPreferPresent(current, next);
2721
+ case "supplementary":
2722
+ return mergeSupplementary(current, next);
2650
2723
  case "coverage_limits":
2651
2724
  return mergeCoverageLimits(current, next);
2652
2725
  case "declarations":
@@ -4243,16 +4316,29 @@ var ContactSchema2 = import_zod33.z.object({
4243
4316
  address: import_zod33.z.string().optional().describe("Mailing address"),
4244
4317
  type: import_zod33.z.string().optional().describe("Contact type, e.g. 'State Department of Insurance'")
4245
4318
  });
4319
+ var AuxiliaryFactSchema2 = import_zod33.z.object({
4320
+ key: import_zod33.z.string().describe("Normalized machine-readable fact key, e.g. 'policyholder_age' or 'insured_name'"),
4321
+ value: import_zod33.z.string().describe("Concrete extracted fact value"),
4322
+ subject: import_zod33.z.string().optional().describe("Person, entity, vehicle, property, or schedule item this fact belongs to"),
4323
+ context: import_zod33.z.string().optional().describe("Short disambiguating context, such as 'Driver Schedule' or 'Named Insured'")
4324
+ });
4246
4325
  var SupplementarySchema = import_zod33.z.object({
4247
4326
  regulatoryContacts: import_zod33.z.array(ContactSchema2).optional().describe("Regulatory body contacts (state department of insurance, ombudsman)"),
4248
4327
  claimsContacts: import_zod33.z.array(ContactSchema2).optional().describe("Claims reporting contacts and instructions"),
4249
4328
  thirdPartyAdministrators: import_zod33.z.array(ContactSchema2).optional().describe("Third-party administrators for claims handling"),
4250
4329
  cancellationNoticeDays: import_zod33.z.number().optional().describe("Required notice period for cancellation in days"),
4251
- nonrenewalNoticeDays: import_zod33.z.number().optional().describe("Required notice period for nonrenewal in days")
4330
+ nonrenewalNoticeDays: import_zod33.z.number().optional().describe("Required notice period for nonrenewal in days"),
4331
+ auxiliaryFacts: import_zod33.z.array(AuxiliaryFactSchema2).optional().describe("Additional retrieval-only facts that do not fit the strict primary schema")
4252
4332
  });
4253
- function buildSupplementaryPrompt() {
4254
- return `You are an expert insurance document analyst. Extract supplementary and regulatory information from this document.
4333
+ function buildSupplementaryPrompt(alreadyExtractedSummary) {
4334
+ const exclusionBlock = alreadyExtractedSummary ? `
4255
4335
 
4336
+ IMPORTANT \u2014 The following facts have ALREADY been captured by prior extraction passes. Do NOT re-extract any of these. Your job is to find ADDITIONAL information that is missing from this list:
4337
+
4338
+ ${alreadyExtractedSummary}
4339
+ ` : "";
4340
+ return `You are an expert insurance document analyst. Extract supplementary, retrieval-only information from this document that is NOT already captured in the structured extraction results.
4341
+ ${exclusionBlock}
4256
4342
  Focus on:
4257
4343
  - Regulatory contacts: state department of insurance, regulatory bodies, ombudsman offices \u2014 with phone, email, address
4258
4344
  - Claims contacts: how to report claims, claims department contact info, hours of operation
@@ -4261,9 +4347,21 @@ Focus on:
4261
4347
  - Nonrenewal notice period in days
4262
4348
  - Complaint filing procedures and contacts
4263
4349
  - Governing law or jurisdiction provisions
4350
+ - Additional policy-specific facts that are useful for memory and retrieval even if they do not belong in the strict primary schema
4264
4351
 
4265
4352
  Look for regulatory notices, complaint contact sections, claims reporting instructions, and cancellation/nonrenewal provisions throughout the document.
4266
4353
 
4354
+ For auxiliaryFacts:
4355
+ - ONLY capture facts that are NOT already present in the structured extraction results above.
4356
+ - Do not duplicate information that has already been extracted \u2014 no policy numbers, insured names, addresses, coverage limits, deductibles, or any other field that appears in the already-extracted data.
4357
+ - Capture concrete, policy-specific facts as structured key/value pairs.
4358
+ - Prioritize facts that agents may need later but that are often omitted from strict schemas: policyholder names, insured person names, driver names, ages, dates of birth, marital status, garaging information, lienholders, household members, vehicle assignments, schedule row details, and other discrete identifiers \u2014 but ONLY if they are not already in the extracted data.
4359
+ - Use short normalized keys like "policyholder_name", "policyholder_age", "insured_name", "driver_age", "driver_date_of_birth", "garaging_zip", "vehicle_principal_driver".
4360
+ - Use subject when the fact belongs to a specific person, vehicle, property, or scheduled item.
4361
+ - Do not invent facts.
4362
+ - Do not include vague boilerplate or generic form language.
4363
+ - Do not repeat large narrative excerpts; keep facts atomic.
4364
+
4267
4365
  Return JSON only.`;
4268
4366
  }
4269
4367
 
@@ -4651,6 +4749,38 @@ function createExtractor(config) {
4651
4749
  sectionCount: Array.isArray(sectionResult?.sections) ? sectionResult.sections.length : 0
4652
4750
  }, null, 2);
4653
4751
  }
4752
+ function buildAlreadyExtractedSummary(memory) {
4753
+ const lines = [];
4754
+ const declarationResult = memory.get("declarations");
4755
+ if (Array.isArray(declarationResult?.fields)) {
4756
+ for (const field of declarationResult.fields) {
4757
+ if (field.key && field.value) {
4758
+ const subject = field.subject ? ` [${field.subject}]` : "";
4759
+ lines.push(`- ${field.key}${subject}: ${field.value}`);
4760
+ }
4761
+ }
4762
+ }
4763
+ const coverageResult = memory.get("coverage_limits");
4764
+ if (Array.isArray(coverageResult?.coverages)) {
4765
+ for (const cov of coverageResult.coverages) {
4766
+ const parts = [cov.name, cov.limit && `limit=${cov.limit}`, cov.deductible && `deductible=${cov.deductible}`].filter(Boolean);
4767
+ if (parts.length > 0) lines.push(`- coverage: ${parts.join(", ")}`);
4768
+ }
4769
+ }
4770
+ const namedInsured = memory.get("named_insured");
4771
+ if (namedInsured) {
4772
+ for (const [key, value] of Object.entries(namedInsured)) {
4773
+ if (value && typeof value === "string") lines.push(`- ${key}: ${value}`);
4774
+ }
4775
+ }
4776
+ const carrierInfo = memory.get("carrier_info");
4777
+ if (carrierInfo) {
4778
+ for (const [key, value] of Object.entries(carrierInfo)) {
4779
+ if (value && typeof value === "string") lines.push(`- ${key}: ${value}`);
4780
+ }
4781
+ }
4782
+ return lines.length > 0 ? lines.join("\n") : "";
4783
+ }
4654
4784
  function formatPageMapSummary(pageAssignments) {
4655
4785
  const extractorPages = /* @__PURE__ */ new Map();
4656
4786
  for (const assignment of pageAssignments) {
@@ -4990,6 +5120,28 @@ function createExtractor(config) {
4990
5120
  mergeMemoryResult(result.name, result.data, memory);
4991
5121
  }
4992
5122
  }
5123
+ {
5124
+ onProgress?.("Extracting supplementary retrieval facts...");
5125
+ try {
5126
+ const alreadyExtractedSummary = buildAlreadyExtractedSummary(memory);
5127
+ const supplementaryResult = await runExtractor({
5128
+ name: "supplementary",
5129
+ prompt: buildSupplementaryPrompt(alreadyExtractedSummary),
5130
+ schema: SupplementarySchema,
5131
+ pdfBase64,
5132
+ startPage: 1,
5133
+ endPage: pageCount,
5134
+ generateObject,
5135
+ convertPdfToImages,
5136
+ maxTokens: 4096,
5137
+ providerOptions
5138
+ });
5139
+ trackUsage(supplementaryResult.usage);
5140
+ mergeMemoryResult(supplementaryResult.name, supplementaryResult.data, memory);
5141
+ } catch (error) {
5142
+ await log?.(`Supplementary extractor failed: ${error}`);
5143
+ }
5144
+ }
4993
5145
  await pipelineCtx.save("extract", {
4994
5146
  id,
4995
5147
  pageCount,
@@ -7706,6 +7858,7 @@ var AGENT_TOOLS = [
7706
7858
  AuditTypeSchema,
7707
7859
  AutoFillMatchSchema,
7708
7860
  AutoFillResultSchema,
7861
+ AuxiliaryFactSchema,
7709
7862
  BOAT_TYPES,
7710
7863
  BindingAuthoritySchema,
7711
7864
  BoatTypeSchema,