@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.mjs CHANGED
@@ -6757,6 +6757,8 @@ For EACH form, extract:
6757
6757
 
6758
6758
  Critical rules:
6759
6759
  - Include declarations page sets even if they do not show a standard form number.
6760
+ - 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.
6761
+ - Declarations pages contain policy-specific schedules such as named insured, policy number, policy period, premium, limits, retentions, coverage parts, or forms-and-endorsements schedules.
6760
6762
  - Use original document page numbers, not local chunk page numbers.
6761
6763
  - Do not emit duplicate entries for repeated headers/footers.
6762
6764
  - Multi-page forms should be represented once with pageStart/pageEnd covering the full span when visible.
@@ -8890,6 +8892,17 @@ function buildTemplateHints(primaryType, documentType, pageCount, template) {
8890
8892
  `Total pages: ${pageCount}`
8891
8893
  ].join("\n");
8892
8894
  }
8895
+ function buildFormInventoryHints(primaryType, documentType, pageCount, template) {
8896
+ return [
8897
+ `Document type: ${primaryType} ${documentType}`,
8898
+ `Expected sections: ${template.expectedSections.join(", ")}`,
8899
+ "Expected source order: jacket/front matter and notices, declarations, policy or coverage form, endorsements/amendatory forms.",
8900
+ "Front matter/notices include policy jackets, claim-reporting notices, privacy notices, OFAC notices, terrorism/TRIA notices, sanctions notices, signatures, countersignatures, and marketing/admin pages.",
8901
+ "Declarations include named insured, policy number, policy period, premium, coverage limits, retentions, forms-and-endorsements schedules, and similar schedule rows.",
8902
+ "Do not classify a page as declarations merely because it appears early in the document.",
8903
+ `Total pages: ${pageCount}`
8904
+ ].join("\n");
8905
+ }
8893
8906
  function groupContiguousPages(pages) {
8894
8907
  if (pages.length === 0) return [];
8895
8908
  const sorted = [...new Set(pages)].sort((a, b) => a - b);
@@ -9311,6 +9324,7 @@ function pageTitleFromText(text, fallback) {
9311
9324
  const endorsement = normalized.match(/\bENDORSEMENT\s+(?:NO\.?|NUMBER|#)\s*[A-Z0-9][A-Z0-9.-]*\b/i)?.[0];
9312
9325
  if (endorsement) return cleanText(endorsement, fallback);
9313
9326
  const firstSentence = normalized.split(/(?<=\.)\s+/)[0];
9327
+ if (/^page\s+\d+\b/i.test(firstSentence)) return fallback;
9314
9328
  if (firstSentence && firstSentence.length <= 120) return firstSentence.replace(/[.]$/, "");
9315
9329
  return fallback;
9316
9330
  }
@@ -9321,7 +9335,16 @@ function pageFormTypeFromText(text) {
9321
9335
  if (/\b(important notice|privacy notice|ofac advisory|terrorism risk insurance act|tria|trade or economic sanctions)\b/i.test(text)) return "notice";
9322
9336
  return "other";
9323
9337
  }
9324
- function inferFormHintsFromSourceSpans(sourceSpans) {
9338
+ function administrativeFormTypeFromText(text) {
9339
+ 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)) {
9340
+ return "notice";
9341
+ }
9342
+ if (/\b(specimen policy|policy jacket|countersigned|countersignature|licensed resident agent|corporate secretary|president and ceo|application of insurance executed)\b/i.test(text)) {
9343
+ return "other";
9344
+ }
9345
+ return void 0;
9346
+ }
9347
+ function pageTextByNumber(sourceSpans) {
9325
9348
  const pageTexts = /* @__PURE__ */ new Map();
9326
9349
  const pageSpanTexts = /* @__PURE__ */ new Map();
9327
9350
  for (const span of sourceSpans) {
@@ -9337,9 +9360,28 @@ function inferFormHintsFromSourceSpans(sourceSpans) {
9337
9360
  if (existing.length < 4e3) pageTexts.set(page, cleanText([existing, span.text].filter(Boolean).join(" "), ""));
9338
9361
  }
9339
9362
  }
9340
- if (pageSpanTexts.size === 0) return [];
9341
- const pageHints = [.../* @__PURE__ */ new Set([...pageTexts.keys(), ...pageSpanTexts.keys()])].sort((left, right) => left - right).map((page) => {
9342
- const text = pageSpanTexts.get(page) ?? pageTexts.get(page) ?? "";
9363
+ return new Map([.../* @__PURE__ */ new Set([...pageTexts.keys(), ...pageSpanTexts.keys()])].map((page) => [
9364
+ page,
9365
+ pageSpanTexts.get(page) ?? pageTexts.get(page) ?? ""
9366
+ ]));
9367
+ }
9368
+ function reconcileFormTypeWithSourceText(form, pageTexts) {
9369
+ const pages = [];
9370
+ const start = form.pageStart;
9371
+ const end = form.pageEnd ?? start;
9372
+ if (typeof start === "number" && typeof end === "number") {
9373
+ for (let page = start; page <= end; page += 1) pages.push(pageTexts.get(page) ?? "");
9374
+ }
9375
+ const text = cleanText([form.title, form.formNumber, ...pages].filter(Boolean).join(" "), "");
9376
+ const administrativeType = administrativeFormTypeFromText(text);
9377
+ if (administrativeType && form.formType !== administrativeType) return administrativeType;
9378
+ return form.formType;
9379
+ }
9380
+ function inferFormHintsFromSourceSpans(sourceSpans) {
9381
+ const pageTexts = pageTextByNumber(sourceSpans);
9382
+ if (pageTexts.size === 0) return [];
9383
+ const pageHints = [...pageTexts.keys()].sort((left, right) => left - right).map((page) => {
9384
+ const text = pageTexts.get(page) ?? "";
9343
9385
  const formNumber = formNumberFromText(text);
9344
9386
  return {
9345
9387
  formNumber,
@@ -9367,10 +9409,12 @@ function inferFormHintsFromSourceSpans(sourceSpans) {
9367
9409
  return merged;
9368
9410
  }
9369
9411
  function normalizeFormHints(forms, sourceSpans) {
9412
+ const pageTexts = pageTextByNumber(sourceSpans);
9370
9413
  const provided = (forms ?? []).filter(
9371
9414
  (form) => typeof form.pageStart === "number" && typeof form.pageEnd === "number" && form.pageStart > 0 && form.pageEnd >= form.pageStart
9372
9415
  ).map((form) => ({
9373
9416
  ...form,
9417
+ formType: reconcileFormTypeWithSourceText(form, pageTexts),
9374
9418
  title: form.title ? cleanText(form.title, "") : void 0
9375
9419
  })).sort(
9376
9420
  (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)
@@ -9545,33 +9589,44 @@ function reparentNodes(sourceTree, childIds, parentId, organizerRepair) {
9545
9589
  function applySemanticPageGrouping(sourceTree) {
9546
9590
  const relabeled = sourceTree.map((node) => {
9547
9591
  if (node.kind === "document" || node.kind === "page_group") return node;
9548
- const endorsement = endorsementStartTitle(node);
9549
- if (endorsement && node.kind === "page") {
9592
+ let nextNode = node;
9593
+ if (node.kind === "page" && /^page\s+\d+$/i.test(node.title)) {
9594
+ const title = pageTitleFromText(sourceNodeText(node), node.title);
9595
+ if (title !== node.title) {
9596
+ nextNode = {
9597
+ ...node,
9598
+ title: simplifyOrganizerTitle(title, title, node.kind),
9599
+ metadata: { ...node.metadata, organizerRepair: "semantic_page_title" }
9600
+ };
9601
+ }
9602
+ }
9603
+ const endorsement = endorsementStartTitle(nextNode);
9604
+ if (endorsement && nextNode.kind === "page") {
9550
9605
  return {
9551
- ...node,
9606
+ ...nextNode,
9552
9607
  kind: "endorsement",
9553
9608
  title: endorsement,
9554
- description: endorsementDescription(endorsement, node),
9555
- metadata: { ...node.metadata, organizerRepair: "semantic_page_grouping" }
9609
+ description: endorsementDescription(endorsement, nextNode),
9610
+ metadata: { ...nextNode.metadata, organizerRepair: "semantic_page_grouping" }
9556
9611
  };
9557
9612
  }
9558
- if (node.kind === "page" && looksLikeDeclarationsStart(node)) {
9613
+ if (nextNode.kind === "page" && looksLikeDeclarationsStart(nextNode)) {
9559
9614
  return {
9560
- ...node,
9615
+ ...nextNode,
9561
9616
  title: "Declarations",
9562
- description: cleanText([node.description, "Declarations"].join(" "), "Declarations"),
9563
- metadata: { ...node.metadata, organizerRepair: "semantic_page_grouping" }
9617
+ description: cleanText([nextNode.description, "Declarations"].join(" "), "Declarations"),
9618
+ metadata: { ...nextNode.metadata, organizerRepair: "semantic_page_grouping" }
9564
9619
  };
9565
9620
  }
9566
- if (node.kind === "page" && looksLikePolicyFormStart(node)) {
9621
+ if (nextNode.kind === "page" && looksLikePolicyFormStart(nextNode)) {
9567
9622
  return {
9568
- ...node,
9623
+ ...nextNode,
9569
9624
  title: "Policy Form",
9570
- description: cleanText([node.description, "Policy Form"].join(" "), "Policy Form"),
9571
- metadata: { ...node.metadata, organizerRepair: "semantic_page_grouping" }
9625
+ description: cleanText([nextNode.description, "Policy Form"].join(" "), "Policy Form"),
9626
+ metadata: { ...nextNode.metadata, organizerRepair: "semantic_page_grouping" }
9572
9627
  };
9573
9628
  }
9574
- return node;
9629
+ return nextNode;
9575
9630
  });
9576
9631
  const rootId = sourceTreeRootId(relabeled);
9577
9632
  const children = (nodesByParent(relabeled).get(rootId) ?? []).filter((node) => node.kind !== "document").sort((left, right) => left.order - right.order);
@@ -10970,7 +11025,7 @@ ${span.text}` : span.text;
10970
11025
  onProgress?.("Building form inventory from source spans...");
10971
11026
  const budget = resolveBudget("extraction_form_inventory", 2048);
10972
11027
  const startedAt = Date.now();
10973
- const templateHints2 = buildTemplateHints("other", "policy", pageCount2, getTemplate("other"));
11028
+ const templateHints2 = buildFormInventoryHints("other", "policy", pageCount2, getTemplate("other"));
10974
11029
  const sourceText = formatSourceSpanText(sourceSpans);
10975
11030
  const prompt = `${buildFormInventoryPrompt(templateHints2)}
10976
11031
 
@@ -11233,7 +11288,9 @@ ${pageText}`;
11233
11288
  const formInventoryResponse = await safeGenerateObject(
11234
11289
  generateObject,
11235
11290
  {
11236
- prompt: withFullDocumentTextContext(buildFormInventoryPrompt(templateHints)),
11291
+ prompt: withFullDocumentTextContext(buildFormInventoryPrompt(
11292
+ buildFormInventoryHints(primaryType, documentType, pageCount, template)
11293
+ )),
11237
11294
  schema: FormInventorySchema,
11238
11295
  maxTokens: budget.maxTokens,
11239
11296
  taskKind: "extraction_form_inventory",