@claritylabs/cl-sdk 3.0.19 → 3.0.21

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
@@ -7104,6 +7104,8 @@ For EACH form, extract:
7104
7104
 
7105
7105
  Critical rules:
7106
7106
  - Include declarations page sets even if they do not show a standard form number.
7107
+ - Do not classify policy jackets, claim-reporting notices, privacy notices, OFAC notices, terrorism/TRIA notices, sanctions notices, signatures, countersignatures, or marketing/admin pages as declarations.
7108
+ - Declarations pages contain policy-specific schedules such as named insured, policy number, policy period, premium, limits, retentions, coverage parts, or forms-and-endorsements schedules.
7107
7109
  - Use original document page numbers, not local chunk page numbers.
7108
7110
  - Do not emit duplicate entries for repeated headers/footers.
7109
7111
  - Multi-page forms should be represented once with pageStart/pageEnd covering the full span when visible.
@@ -9237,6 +9239,17 @@ function buildTemplateHints(primaryType, documentType, pageCount, template) {
9237
9239
  `Total pages: ${pageCount}`
9238
9240
  ].join("\n");
9239
9241
  }
9242
+ function buildFormInventoryHints(primaryType, documentType, pageCount, template) {
9243
+ return [
9244
+ `Document type: ${primaryType} ${documentType}`,
9245
+ `Expected sections: ${template.expectedSections.join(", ")}`,
9246
+ "Expected source order: jacket/front matter and notices, declarations, policy or coverage form, endorsements/amendatory forms.",
9247
+ "Front matter/notices include policy jackets, claim-reporting notices, privacy notices, OFAC notices, terrorism/TRIA notices, sanctions notices, signatures, countersignatures, and marketing/admin pages.",
9248
+ "Declarations include named insured, policy number, policy period, premium, coverage limits, retentions, forms-and-endorsements schedules, and similar schedule rows.",
9249
+ "Do not classify a page as declarations merely because it appears early in the document.",
9250
+ `Total pages: ${pageCount}`
9251
+ ].join("\n");
9252
+ }
9240
9253
  function groupContiguousPages(pages) {
9241
9254
  if (pages.length === 0) return [];
9242
9255
  const sorted = [...new Set(pages)].sort((a, b) => a - b);
@@ -9658,6 +9671,7 @@ function pageTitleFromText(text, fallback) {
9658
9671
  const endorsement = normalized.match(/\bENDORSEMENT\s+(?:NO\.?|NUMBER|#)\s*[A-Z0-9][A-Z0-9.-]*\b/i)?.[0];
9659
9672
  if (endorsement) return cleanText(endorsement, fallback);
9660
9673
  const firstSentence = normalized.split(/(?<=\.)\s+/)[0];
9674
+ if (/^page\s+\d+\b/i.test(firstSentence)) return fallback;
9661
9675
  if (firstSentence && firstSentence.length <= 120) return firstSentence.replace(/[.]$/, "");
9662
9676
  return fallback;
9663
9677
  }
@@ -9668,7 +9682,16 @@ function pageFormTypeFromText(text) {
9668
9682
  if (/\b(important notice|privacy notice|ofac advisory|terrorism risk insurance act|tria|trade or economic sanctions)\b/i.test(text)) return "notice";
9669
9683
  return "other";
9670
9684
  }
9671
- function inferFormHintsFromSourceSpans(sourceSpans) {
9685
+ function administrativeFormTypeFromText(text) {
9686
+ if (/\b(important notice|privacy notice|ofac advisory|terrorism risk insurance act|tria|trade or economic sanctions|economic sanctions limitation|how to report a claim)\b/i.test(text)) {
9687
+ return "notice";
9688
+ }
9689
+ if (/\b(specimen policy|policy jacket|countersigned|countersignature|licensed resident agent|corporate secretary|president and ceo|application of insurance executed)\b/i.test(text)) {
9690
+ return "other";
9691
+ }
9692
+ return void 0;
9693
+ }
9694
+ function pageTextByNumber(sourceSpans) {
9672
9695
  const pageTexts = /* @__PURE__ */ new Map();
9673
9696
  const pageSpanTexts = /* @__PURE__ */ new Map();
9674
9697
  for (const span of sourceSpans) {
@@ -9684,9 +9707,28 @@ function inferFormHintsFromSourceSpans(sourceSpans) {
9684
9707
  if (existing.length < 4e3) pageTexts.set(page, cleanText([existing, span.text].filter(Boolean).join(" "), ""));
9685
9708
  }
9686
9709
  }
9687
- if (pageSpanTexts.size === 0) return [];
9688
- const pageHints = [.../* @__PURE__ */ new Set([...pageTexts.keys(), ...pageSpanTexts.keys()])].sort((left, right) => left - right).map((page) => {
9689
- const text = pageSpanTexts.get(page) ?? pageTexts.get(page) ?? "";
9710
+ return new Map([.../* @__PURE__ */ new Set([...pageTexts.keys(), ...pageSpanTexts.keys()])].map((page) => [
9711
+ page,
9712
+ pageSpanTexts.get(page) ?? pageTexts.get(page) ?? ""
9713
+ ]));
9714
+ }
9715
+ function reconcileFormTypeWithSourceText(form, pageTexts) {
9716
+ const pages = [];
9717
+ const start = form.pageStart;
9718
+ const end = form.pageEnd ?? start;
9719
+ if (typeof start === "number" && typeof end === "number") {
9720
+ for (let page = start; page <= end; page += 1) pages.push(pageTexts.get(page) ?? "");
9721
+ }
9722
+ const text = cleanText([form.title, form.formNumber, ...pages].filter(Boolean).join(" "), "");
9723
+ const administrativeType = administrativeFormTypeFromText(text);
9724
+ if (administrativeType && form.formType !== administrativeType) return administrativeType;
9725
+ return form.formType;
9726
+ }
9727
+ function inferFormHintsFromSourceSpans(sourceSpans) {
9728
+ const pageTexts = pageTextByNumber(sourceSpans);
9729
+ if (pageTexts.size === 0) return [];
9730
+ const pageHints = [...pageTexts.keys()].sort((left, right) => left - right).map((page) => {
9731
+ const text = pageTexts.get(page) ?? "";
9690
9732
  const formNumber = formNumberFromText(text);
9691
9733
  return {
9692
9734
  formNumber,
@@ -9714,10 +9756,12 @@ function inferFormHintsFromSourceSpans(sourceSpans) {
9714
9756
  return merged;
9715
9757
  }
9716
9758
  function normalizeFormHints(forms, sourceSpans) {
9759
+ const pageTexts = pageTextByNumber(sourceSpans);
9717
9760
  const provided = (forms ?? []).filter(
9718
9761
  (form) => typeof form.pageStart === "number" && typeof form.pageEnd === "number" && form.pageStart > 0 && form.pageEnd >= form.pageStart
9719
9762
  ).map((form) => ({
9720
9763
  ...form,
9764
+ formType: reconcileFormTypeWithSourceText(form, pageTexts),
9721
9765
  title: form.title ? cleanText(form.title, "") : void 0
9722
9766
  })).sort(
9723
9767
  (left, right) => (left.pageStart ?? Number.MAX_SAFE_INTEGER) - (right.pageStart ?? Number.MAX_SAFE_INTEGER) || (left.pageEnd ?? Number.MAX_SAFE_INTEGER) - (right.pageEnd ?? Number.MAX_SAFE_INTEGER)
@@ -9892,33 +9936,44 @@ function reparentNodes(sourceTree, childIds, parentId, organizerRepair) {
9892
9936
  function applySemanticPageGrouping(sourceTree) {
9893
9937
  const relabeled = sourceTree.map((node) => {
9894
9938
  if (node.kind === "document" || node.kind === "page_group") return node;
9895
- const endorsement = endorsementStartTitle(node);
9896
- if (endorsement && node.kind === "page") {
9939
+ let nextNode = node;
9940
+ if (node.kind === "page" && /^page\s+\d+$/i.test(node.title)) {
9941
+ const title = pageTitleFromText(sourceNodeText(node), node.title);
9942
+ if (title !== node.title) {
9943
+ nextNode = {
9944
+ ...node,
9945
+ title: simplifyOrganizerTitle(title, title, node.kind),
9946
+ metadata: { ...node.metadata, organizerRepair: "semantic_page_title" }
9947
+ };
9948
+ }
9949
+ }
9950
+ const endorsement = endorsementStartTitle(nextNode);
9951
+ if (endorsement && nextNode.kind === "page") {
9897
9952
  return {
9898
- ...node,
9953
+ ...nextNode,
9899
9954
  kind: "endorsement",
9900
9955
  title: endorsement,
9901
- description: endorsementDescription(endorsement, node),
9902
- metadata: { ...node.metadata, organizerRepair: "semantic_page_grouping" }
9956
+ description: endorsementDescription(endorsement, nextNode),
9957
+ metadata: { ...nextNode.metadata, organizerRepair: "semantic_page_grouping" }
9903
9958
  };
9904
9959
  }
9905
- if (node.kind === "page" && looksLikeDeclarationsStart(node)) {
9960
+ if (nextNode.kind === "page" && looksLikeDeclarationsStart(nextNode)) {
9906
9961
  return {
9907
- ...node,
9962
+ ...nextNode,
9908
9963
  title: "Declarations",
9909
- description: cleanText([node.description, "Declarations"].join(" "), "Declarations"),
9910
- metadata: { ...node.metadata, organizerRepair: "semantic_page_grouping" }
9964
+ description: cleanText([nextNode.description, "Declarations"].join(" "), "Declarations"),
9965
+ metadata: { ...nextNode.metadata, organizerRepair: "semantic_page_grouping" }
9911
9966
  };
9912
9967
  }
9913
- if (node.kind === "page" && looksLikePolicyFormStart(node)) {
9968
+ if (nextNode.kind === "page" && looksLikePolicyFormStart(nextNode)) {
9914
9969
  return {
9915
- ...node,
9970
+ ...nextNode,
9916
9971
  title: "Policy Form",
9917
- description: cleanText([node.description, "Policy Form"].join(" "), "Policy Form"),
9918
- metadata: { ...node.metadata, organizerRepair: "semantic_page_grouping" }
9972
+ description: cleanText([nextNode.description, "Policy Form"].join(" "), "Policy Form"),
9973
+ metadata: { ...nextNode.metadata, organizerRepair: "semantic_page_grouping" }
9919
9974
  };
9920
9975
  }
9921
- return node;
9976
+ return nextNode;
9922
9977
  });
9923
9978
  const rootId = sourceTreeRootId(relabeled);
9924
9979
  const children = (nodesByParent(relabeled).get(rootId) ?? []).filter((node) => node.kind !== "document").sort((left, right) => left.order - right.order);
@@ -11317,7 +11372,7 @@ ${span.text}` : span.text;
11317
11372
  onProgress?.("Building form inventory from source spans...");
11318
11373
  const budget = resolveBudget("extraction_form_inventory", 2048);
11319
11374
  const startedAt = Date.now();
11320
- const templateHints2 = buildTemplateHints("other", "policy", pageCount2, getTemplate("other"));
11375
+ const templateHints2 = buildFormInventoryHints("other", "policy", pageCount2, getTemplate("other"));
11321
11376
  const sourceText = formatSourceSpanText(sourceSpans);
11322
11377
  const prompt = `${buildFormInventoryPrompt(templateHints2)}
11323
11378
 
@@ -11580,7 +11635,9 @@ ${pageText}`;
11580
11635
  const formInventoryResponse = await safeGenerateObject(
11581
11636
  generateObject,
11582
11637
  {
11583
- prompt: withFullDocumentTextContext(buildFormInventoryPrompt(templateHints)),
11638
+ prompt: withFullDocumentTextContext(buildFormInventoryPrompt(
11639
+ buildFormInventoryHints(primaryType, documentType, pageCount, template)
11640
+ )),
11584
11641
  schema: FormInventorySchema,
11585
11642
  maxTokens: budget.maxTokens,
11586
11643
  taskKind: "extraction_form_inventory",