@claritylabs/cl-sdk 3.2.1 → 3.2.3

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
@@ -3918,7 +3918,7 @@ function mergeOperationalProfile(base, candidate, validNodeIds, validSpanIds) {
3918
3918
  ];
3919
3919
  return PolicyOperationalProfileSchema.parse({
3920
3920
  ...base,
3921
- documentType: candidate.documentType === "quote" ? "quote" : candidate.documentType === "policy" ? "policy" : base.documentType,
3921
+ documentType: candidate.documentType === "policy" ? "policy" : base.documentType,
3922
3922
  policyTypes: Array.isArray(candidate.policyTypes) && candidate.policyTypes.length > 0 ? candidate.policyTypes : base.policyTypes,
3923
3923
  policyNumber,
3924
3924
  namedInsured,
@@ -5544,6 +5544,94 @@ function nodesByParent(sourceTree) {
5544
5544
  }
5545
5545
  return byParent;
5546
5546
  }
5547
+ function sourceNodeIdsBySpanId(sourceTree) {
5548
+ const bySpan = /* @__PURE__ */ new Map();
5549
+ for (const node of sourceTree) {
5550
+ for (const spanId of node.sourceSpanIds) {
5551
+ const nodes = bySpan.get(spanId) ?? [];
5552
+ nodes.push(node.id);
5553
+ bySpan.set(spanId, nodes);
5554
+ }
5555
+ }
5556
+ return bySpan;
5557
+ }
5558
+ function operationalEvidenceScore(span) {
5559
+ const text = cleanText([
5560
+ span.text,
5561
+ span.formNumber,
5562
+ span.sourceUnit,
5563
+ span.metadata?.elementType,
5564
+ span.metadata?.sourceUnit
5565
+ ].filter(Boolean).join(" "), "");
5566
+ if (!text) return 0;
5567
+ let score = 0;
5568
+ if (span.sourceUnit === "table_row" || span.sourceUnit === "table") score += 5;
5569
+ if (span.metadata?.elementType === "title") score += 4;
5570
+ if (span.sourceUnit === "page") score -= 3;
5571
+ if (/\b(policy\s*(number|period|term)|effective date|expiration date|expiry date|named insured|insurer|carrier|security|broker|producer|premium|total due)\b/i.test(text)) score += 12;
5572
+ if (/\b(coverage part|limit(?:s)? of liability|deductible|retention|retroactive date|aggregate|sublimit|sub-limit|each claim|each loss|each occurrence|coinsurance)\b/i.test(text)) score += 14;
5573
+ if (/\bendorsement\s+(?:no\.?|number|#)?\s*[A-Z0-9]|forms? and endorsements?|attached at inception|schedule\b/i.test(text)) score += 8;
5574
+ if (/\bitem\s+\d+\.?\s*(?:named insured|policy number|policy period|renewal|form of business|coverage parts?|premium|extended reporting|producer|forms? and endorsements?)\b/i.test(text)) score += 10;
5575
+ if (/\$[\d,.]+|[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{2,4}|[0-9]{1,2}\s+[A-Za-z]{3,9}\s+[0-9]{4}/.test(text)) score += 3;
5576
+ return score;
5577
+ }
5578
+ function spanTableId(span) {
5579
+ return span.table?.tableId ?? span.metadata?.tableId;
5580
+ }
5581
+ function isTableCellSpan(span) {
5582
+ return spanSourceUnit(span) === "table_cell";
5583
+ }
5584
+ function operationalProfileEvidence(sourceTree, sourceSpans) {
5585
+ const sorted = [...sourceSpans].sort(
5586
+ (left, right) => (spanPageStart(left) ?? Number.MAX_SAFE_INTEGER) - (spanPageStart(right) ?? Number.MAX_SAFE_INTEGER) || (left.location?.charStart ?? Number.MAX_SAFE_INTEGER) - (right.location?.charStart ?? Number.MAX_SAFE_INTEGER) || left.id.localeCompare(right.id)
5587
+ );
5588
+ const selected = /* @__PURE__ */ new Set();
5589
+ const selectedTableIds = /* @__PURE__ */ new Set();
5590
+ for (let index = 0; index < sorted.length; index += 1) {
5591
+ const score = operationalEvidenceScore(sorted[index]);
5592
+ if (score < 8) continue;
5593
+ const tableId2 = spanTableId(sorted[index]);
5594
+ if (tableId2 && !isTableCellSpan(sorted[index])) selectedTableIds.add(tableId2);
5595
+ const page = spanPageStart(sorted[index]);
5596
+ for (let offset = -2; offset <= 2; offset += 1) {
5597
+ const neighborIndex = index + offset;
5598
+ const neighbor = sorted[neighborIndex];
5599
+ if (!neighbor || spanPageStart(neighbor) !== page) continue;
5600
+ const neighborText = cleanText(neighbor.text, "");
5601
+ if (!neighborText || neighborText.length > 5e3) continue;
5602
+ selected.add(neighborIndex);
5603
+ }
5604
+ }
5605
+ if (selectedTableIds.size > 0) {
5606
+ sorted.forEach((span, index) => {
5607
+ const tableId2 = spanTableId(span);
5608
+ if (!tableId2 || !selectedTableIds.has(tableId2) || isTableCellSpan(span)) return;
5609
+ const text = cleanText(span.text, "");
5610
+ if (text && text.length <= 5e3) selected.add(index);
5611
+ });
5612
+ }
5613
+ const nodeIdsBySpanId = sourceNodeIdsBySpanId(sourceTree);
5614
+ const seenText = /* @__PURE__ */ new Set();
5615
+ const entries = [...selected].sort((left, right) => left - right).map((index) => sorted[index]).filter((span) => !isTableCellSpan(span)).flatMap((span) => {
5616
+ const text = cleanText(span.text, "");
5617
+ if (!text) return [];
5618
+ const key = `${spanPageStart(span) ?? "na"}:${text.toLowerCase().slice(0, 240)}`;
5619
+ if (seenText.has(key)) return [];
5620
+ seenText.add(key);
5621
+ return [{
5622
+ sourceSpanId: span.id,
5623
+ sourceNodeIds: [...new Set(nodeIdsBySpanId.get(span.id) ?? [])].slice(0, 4),
5624
+ pageStart: spanPageStart(span),
5625
+ pageEnd: spanPageEnd(span),
5626
+ sourceUnit: spanSourceUnit(span),
5627
+ formNumber: span.formNumber,
5628
+ text: text.slice(0, span.sourceUnit === "page" ? 1200 : 900)
5629
+ }];
5630
+ });
5631
+ const detailEntries = entries.filter((entry) => entry.sourceUnit !== "page");
5632
+ const pageEntries = entries.filter((entry) => entry.sourceUnit === "page");
5633
+ return (detailEntries.length >= 20 ? detailEntries : [...detailEntries, ...pageEntries]).slice(0, 180);
5634
+ }
5547
5635
  function sourceTreeRootId(sourceTree) {
5548
5636
  return sourceTree.find((node) => node.kind === "document")?.id;
5549
5637
  }
@@ -5568,11 +5656,12 @@ function emptyOperationalProfile() {
5568
5656
  warnings: []
5569
5657
  };
5570
5658
  }
5571
- function buildOperationalProfilePrompt(sourceTree) {
5572
- const nodes = operationalProfilePromptNodes(sourceTree).map(
5659
+ function buildOperationalProfilePrompt(sourceTree, sourceSpans) {
5660
+ const evidence = operationalProfileEvidence(sourceTree, sourceSpans);
5661
+ const fallbackNodes = evidence.length ? [] : operationalProfilePromptNodes(sourceTree).map(
5573
5662
  (node) => compactNode2(node, node.kind === "page" || node.kind === "endorsement" ? 900 : 700)
5574
5663
  );
5575
- return `Extract a source-backed operational profile for an insurance policy or quote.
5664
+ return `Extract a source-backed operational profile for an insurance policy.
5576
5665
 
5577
5666
  Return only high-value operational facts needed for policy lists, Q&A, compliance, and certificate generation:
5578
5667
  - policy number, named insured, insurer/carrier/security, broker/producer, policy period, retroactive date, premium
@@ -5580,7 +5669,8 @@ Return only high-value operational facts needed for policy lists, Q&A, complianc
5580
5669
  - coverage type labels
5581
5670
 
5582
5671
  Rules:
5583
- - Every returned value must include sourceNodeIds or sourceSpanIds from the provided nodes.
5672
+ - Every returned value must include sourceNodeIds or sourceSpanIds from the provided evidence.
5673
+ - When citing an evidence entry, copy its sourceSpanId into the returned sourceSpanIds array.
5584
5674
  - If a value is not directly supported, omit it.
5585
5675
  - Prefer declarations, schedules, premium tables, and endorsement schedules over generic policy wording.
5586
5676
  - For broker/producer, extract the agency or company legal name, not the license role, credential, or type. In a block like "Bayshore Insurance Brokers, LLC" followed by "Surplus Lines Broker - CA License No. ...", broker.value must be "Bayshore Insurance Brokers, LLC"; the surplus-lines role and license number are not the broker name.
@@ -5596,10 +5686,10 @@ Rules:
5596
5686
  - For coverage schedules, put each claim, aggregate, sublimit, retention, deductible, and retroactive date values in coverages[].limits with labels and source IDs. Keep the legacy coverages[].limit as the primary display value only.
5597
5687
  - Extract coinsurance, participation percentage, or insurer/named-insured split terms as coverages[].limits entries with kind "other" when they are part of a coverage schedule.
5598
5688
  - Do not copy entire policy wording into fields.
5599
- - Extract facts directly from source nodes. There is no deterministic fact baseline.
5689
+ - Extract facts directly from source evidence. There is no deterministic fact baseline.
5600
5690
 
5601
- Source nodes:
5602
- ${JSON.stringify(nodes, null, 2)}
5691
+ Source evidence:
5692
+ ${JSON.stringify(evidence.length ? evidence : fallbackNodes, null, 2)}
5603
5693
 
5604
5694
  Return JSON for the operational profile.`;
5605
5695
  }
@@ -5859,7 +5949,7 @@ async function runSourceTreeExtraction(params) {
5859
5949
  const response = await safeGenerateObject(
5860
5950
  params.generateObject,
5861
5951
  {
5862
- prompt: buildOperationalProfilePrompt(sourceTree),
5952
+ prompt: buildOperationalProfilePrompt(sourceTree, sourceSpans),
5863
5953
  schema: OperationalProfilePromptSchema,
5864
5954
  maxTokens: budget.maxTokens,
5865
5955
  taskKind: "extraction_operational_profile",