@claritylabs/cl-sdk 1.2.1 → 1.3.2

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
@@ -559,7 +559,8 @@ function resolveModelBudget(params) {
559
559
  const schemaTokens = estimateTokens(params.schemaSizeBytes) ?? 0;
560
560
  const expectedListLength = positiveInteger(params.expectedListLength) ?? 0;
561
561
  const warnings = [];
562
- let maxTokens = constrainedPreference ?? taskCapability ?? longListCapability ?? defaultCapability ?? hintTokens;
562
+ const preferredOutputTokens = constrainedPreference ?? taskCapability ?? longListCapability ?? defaultCapability ?? hintTokens;
563
+ let maxTokens = hardMaxOutputTokens ?? modelMaxOutputTokens ?? preferredOutputTokens;
563
564
  if (minOutputTokens) {
564
565
  maxTokens = Math.max(maxTokens, minOutputTokens);
565
566
  }
@@ -588,6 +589,7 @@ function resolveModelBudget(params) {
588
589
  taskKind,
589
590
  maxTokens,
590
591
  hintTokens,
592
+ preferredOutputTokens,
591
593
  modelMaxOutputTokens,
592
594
  hardMaxOutputTokens,
593
595
  estimatedInputTokens,
@@ -1009,7 +1011,8 @@ var EndorsementSchema = import_zod5.z.object({
1009
1011
  namedParties: import_zod5.z.array(EndorsementPartySchema).optional(),
1010
1012
  keyTerms: import_zod5.z.array(import_zod5.z.string()).optional(),
1011
1013
  premiumImpact: import_zod5.z.string().optional(),
1012
- content: import_zod5.z.string(),
1014
+ excerpt: import_zod5.z.string().optional(),
1015
+ content: import_zod5.z.string().optional(),
1013
1016
  pageStart: import_zod5.z.number(),
1014
1017
  pageEnd: import_zod5.z.number().optional(),
1015
1018
  recordId: import_zod5.z.string().optional(),
@@ -1622,7 +1625,10 @@ var SubsectionSchema = import_zod16.z.object({
1622
1625
  title: import_zod16.z.string(),
1623
1626
  sectionNumber: import_zod16.z.string().optional(),
1624
1627
  pageNumber: import_zod16.z.number().optional(),
1625
- content: import_zod16.z.string()
1628
+ excerpt: import_zod16.z.string().optional(),
1629
+ content: import_zod16.z.string().optional(),
1630
+ sourceSpanIds: import_zod16.z.array(import_zod16.z.string()).optional(),
1631
+ sourceTextHash: import_zod16.z.string().optional()
1626
1632
  });
1627
1633
  var SectionSchema = import_zod16.z.object({
1628
1634
  title: import_zod16.z.string(),
@@ -1631,7 +1637,8 @@ var SectionSchema = import_zod16.z.object({
1631
1637
  pageEnd: import_zod16.z.number().optional(),
1632
1638
  type: import_zod16.z.string(),
1633
1639
  coverageType: import_zod16.z.string().optional(),
1634
- content: import_zod16.z.string(),
1640
+ excerpt: import_zod16.z.string().optional(),
1641
+ content: import_zod16.z.string().optional(),
1635
1642
  subsections: import_zod16.z.array(SubsectionSchema).optional(),
1636
1643
  recordId: import_zod16.z.string().optional(),
1637
1644
  sourceSpanIds: import_zod16.z.array(import_zod16.z.string()).optional(),
@@ -3141,6 +3148,14 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
3141
3148
  maxTokens,
3142
3149
  taskKind,
3143
3150
  budgetDiagnostics,
3151
+ trace: {
3152
+ label: `${name} pages ${startPage}-${endPage}`,
3153
+ extractorName: name,
3154
+ startPage,
3155
+ endPage,
3156
+ phase: "extractor",
3157
+ sourceBacked: !!sourceContext
3158
+ },
3144
3159
  providerOptions: extractorProviderOptions
3145
3160
  })
3146
3161
  );
@@ -4006,21 +4021,30 @@ function collectContentFields(doc) {
4006
4021
  entries.push({ id: id++, path, text });
4007
4022
  }
4008
4023
  }
4024
+ function hasSourceBacking(record) {
4025
+ return Array.isArray(record.sourceSpanIds) && record.sourceSpanIds.length > 0 || !!record.sourceTextHash;
4026
+ }
4009
4027
  add("summary", doc.summary);
4010
4028
  if (doc.sections) {
4011
4029
  for (let i = 0; i < doc.sections.length; i++) {
4012
4030
  const s = doc.sections[i];
4013
- add(`sections[${i}].content`, s.content);
4031
+ if (!hasSourceBacking(s)) {
4032
+ add(`sections[${i}].content`, s.content);
4033
+ }
4014
4034
  if (s.subsections) {
4015
4035
  for (let j = 0; j < s.subsections.length; j++) {
4016
- add(`sections[${i}].subsections[${j}].content`, s.subsections[j].content);
4036
+ if (!hasSourceBacking(s.subsections[j])) {
4037
+ add(`sections[${i}].subsections[${j}].content`, s.subsections[j].content);
4038
+ }
4017
4039
  }
4018
4040
  }
4019
4041
  }
4020
4042
  }
4021
4043
  if (doc.endorsements) {
4022
4044
  for (let i = 0; i < doc.endorsements.length; i++) {
4023
- add(`endorsements[${i}].content`, doc.endorsements[i].content);
4045
+ if (!hasSourceBacking(doc.endorsements[i])) {
4046
+ add(`endorsements[${i}].content`, doc.endorsements[i].content);
4047
+ }
4024
4048
  }
4025
4049
  }
4026
4050
  if (doc.exclusions) {
@@ -4122,6 +4146,12 @@ async function formatDocumentContent(doc, generateText, options) {
4122
4146
  maxTokens: options?.maxTokens ?? 16384,
4123
4147
  taskKind: options?.taskKind,
4124
4148
  budgetDiagnostics: options?.budgetDiagnostics,
4149
+ trace: {
4150
+ label: `format content batch ${batchIdx + 1}/${batches.length}`,
4151
+ phase: "format",
4152
+ batchIndex: batchIdx + 1,
4153
+ batchCount: batches.length
4154
+ },
4125
4155
  providerOptions: options?.providerOptions
4126
4156
  })
4127
4157
  );
@@ -4196,7 +4226,7 @@ function chunkDocument(doc) {
4196
4226
  documentId: docId,
4197
4227
  type,
4198
4228
  text,
4199
- metadata: stringMetadata(metadata)
4229
+ metadata: stringMetadata({ evidenceKind: "structured_fact", ...metadata })
4200
4230
  });
4201
4231
  }
4202
4232
  pushChunk(
@@ -4475,16 +4505,29 @@ function chunkDocument(doc) {
4475
4505
  );
4476
4506
  });
4477
4507
  doc.endorsements?.forEach((end, i) => {
4508
+ const text = lines([
4509
+ `Endorsement: ${end.title}`,
4510
+ end.formNumber ? `Form: ${end.formNumber}` : null,
4511
+ end.editionDate ? `Edition: ${end.editionDate}` : null,
4512
+ `Type: ${end.endorsementType}`,
4513
+ end.effectiveDate ? `Effective Date: ${end.effectiveDate}` : null,
4514
+ end.affectedCoverageParts?.length ? `Affected Coverage Parts: ${end.affectedCoverageParts.join(", ")}` : null,
4515
+ end.keyTerms?.length ? `Key Terms: ${end.keyTerms.join("; ")}` : null,
4516
+ end.premiumImpact ? `Premium Impact: ${end.premiumImpact}` : null,
4517
+ end.excerpt ? `Excerpt: ${end.excerpt}` : null
4518
+ ]);
4519
+ if (!text.trim()) return;
4478
4520
  pushChunk(
4479
4521
  `endorsement:${i}`,
4480
4522
  "endorsement",
4481
- `Endorsement: ${end.title}
4482
- ${end.content}`.trim(),
4523
+ text,
4483
4524
  {
4484
4525
  endorsementType: end.endorsementType,
4485
4526
  formNumber: end.formNumber,
4486
4527
  pageStart: end.pageStart,
4487
4528
  pageEnd: end.pageEnd,
4529
+ sourceSpanIds: end.sourceSpanIds?.join(","),
4530
+ sourceTextHash: end.sourceTextHash,
4488
4531
  documentType: doc.type
4489
4532
  }
4490
4533
  );
@@ -4606,93 +4649,51 @@ ${declLines.join("\n")}`, declMeta);
4606
4649
  }
4607
4650
  doc.sections?.forEach((sec, i) => {
4608
4651
  const hasSubsections = sec.subsections && sec.subsections.length > 0;
4609
- const contentLength = sec.content.length;
4610
- if (hasSubsections) {
4611
- pushChunk(
4612
- `section:${i}`,
4613
- "section",
4614
- `Section: ${sec.title}
4615
- ${sec.content}`,
4616
- {
4617
- sectionType: sec.type,
4618
- sectionNumber: sec.sectionNumber,
4619
- pageStart: sec.pageStart,
4620
- pageEnd: sec.pageEnd,
4621
- documentType: doc.type,
4622
- hasSubsections: "true"
4623
- }
4624
- );
4625
- sec.subsections.forEach((sub, j) => {
4626
- pushChunk(
4627
- `section:${i}:sub:${j}`,
4628
- "section",
4629
- `${sec.title} > ${sub.title}
4630
- ${sub.content}`,
4631
- {
4632
- sectionType: sec.type,
4633
- parentSection: sec.title,
4634
- sectionNumber: sub.sectionNumber,
4635
- pageNumber: sub.pageNumber,
4636
- documentType: doc.type
4637
- }
4638
- );
4639
- });
4640
- } else if (contentLength > 2e3) {
4641
- const paragraphs = sec.content.split(/\n\n+/);
4642
- let currentChunk = "";
4643
- let chunkIndex = 0;
4644
- for (const para of paragraphs) {
4645
- if (currentChunk.length + para.length > 1e3 && currentChunk.length > 0) {
4646
- pushChunk(
4647
- `section:${i}:part:${chunkIndex}`,
4648
- "section",
4649
- `Section: ${sec.title} (part ${chunkIndex + 1})
4650
- ${currentChunk.trim()}`,
4651
- {
4652
- sectionType: sec.type,
4653
- sectionNumber: sec.sectionNumber,
4654
- pageStart: sec.pageStart,
4655
- pageEnd: sec.pageEnd,
4656
- documentType: doc.type,
4657
- partIndex: chunkIndex
4658
- }
4659
- );
4660
- currentChunk = "";
4661
- chunkIndex++;
4662
- }
4663
- currentChunk += (currentChunk ? "\n\n" : "") + para;
4664
- }
4665
- if (currentChunk.trim()) {
4666
- pushChunk(
4667
- `section:${i}:part:${chunkIndex}`,
4668
- "section",
4669
- `Section: ${sec.title} (part ${chunkIndex + 1})
4670
- ${currentChunk.trim()}`,
4671
- {
4672
- sectionType: sec.type,
4673
- sectionNumber: sec.sectionNumber,
4674
- pageStart: sec.pageStart,
4675
- pageEnd: sec.pageEnd,
4676
- documentType: doc.type,
4677
- partIndex: chunkIndex
4678
- }
4679
- );
4652
+ pushChunk(
4653
+ `section:${i}`,
4654
+ "section",
4655
+ lines([
4656
+ `Section: ${sec.title}`,
4657
+ `Type: ${sec.type}`,
4658
+ sec.sectionNumber ? `Section Number: ${sec.sectionNumber}` : null,
4659
+ `Pages: ${sec.pageStart}${sec.pageEnd ? `-${sec.pageEnd}` : ""}`,
4660
+ sec.excerpt ? `Excerpt: ${sec.excerpt}` : null,
4661
+ hasSubsections ? `Subsections: ${sec.subsections.map((sub) => sub.title).join(", ")}` : null
4662
+ ]),
4663
+ {
4664
+ evidenceKind: "navigation",
4665
+ sectionType: sec.type,
4666
+ sectionNumber: sec.sectionNumber,
4667
+ pageStart: sec.pageStart,
4668
+ pageEnd: sec.pageEnd,
4669
+ sourceSpanIds: sec.sourceSpanIds?.join(","),
4670
+ sourceTextHash: sec.sourceTextHash,
4671
+ documentType: doc.type,
4672
+ hasSubsections
4680
4673
  }
4681
- } else {
4674
+ );
4675
+ sec.subsections?.forEach((sub, j) => {
4682
4676
  pushChunk(
4683
- `section:${i}`,
4677
+ `section:${i}:sub:${j}`,
4684
4678
  "section",
4685
- `Section: ${sec.title}
4686
- ${sec.content}`,
4679
+ lines([
4680
+ `Section: ${sec.title} > ${sub.title}`,
4681
+ sub.sectionNumber ? `Section Number: ${sub.sectionNumber}` : null,
4682
+ sub.pageNumber ? `Page: ${sub.pageNumber}` : null,
4683
+ sub.excerpt ? `Excerpt: ${sub.excerpt}` : null
4684
+ ]),
4687
4685
  {
4686
+ evidenceKind: "navigation",
4688
4687
  sectionType: sec.type,
4689
- sectionNumber: sec.sectionNumber,
4690
- pageStart: sec.pageStart,
4691
- pageEnd: sec.pageEnd,
4688
+ parentSection: sec.title,
4689
+ sectionNumber: sub.sectionNumber,
4690
+ pageNumber: sub.pageNumber,
4691
+ sourceSpanIds: sub.sourceSpanIds?.join(","),
4692
+ sourceTextHash: sub.sourceTextHash,
4692
4693
  documentType: doc.type
4693
4694
  }
4694
4695
  );
4695
- }
4696
+ });
4696
4697
  });
4697
4698
  doc.locations?.forEach((loc, i) => {
4698
4699
  chunks.push({
@@ -6564,14 +6565,17 @@ var EndorsementsSchema = import_zod29.z.object({
6564
6565
  ).optional().describe("Named parties (additional insureds, loss payees, etc.)"),
6565
6566
  keyTerms: import_zod29.z.array(import_zod29.z.string()).optional().describe("Key terms or notable provisions in the endorsement"),
6566
6567
  premiumImpact: import_zod29.z.string().optional().describe("Additional premium or credit"),
6567
- content: import_zod29.z.string().describe("Full verbatim text of the endorsement"),
6568
+ excerpt: import_zod29.z.string().optional().describe("Short source excerpt, not full verbatim text"),
6569
+ content: import_zod29.z.string().optional().describe("Legacy fallback only; do not return full text when sourceSpanIds are available"),
6568
6570
  pageStart: import_zod29.z.number().describe("Starting page number of this endorsement"),
6569
- pageEnd: import_zod29.z.number().optional().describe("Ending page number of this endorsement")
6571
+ pageEnd: import_zod29.z.number().optional().describe("Ending page number of this endorsement"),
6572
+ sourceSpanIds: import_zod29.z.array(import_zod29.z.string()).optional().describe("Source span IDs grounding this endorsement"),
6573
+ sourceTextHash: import_zod29.z.string().optional().describe("Hash of the source text when available")
6570
6574
  })
6571
6575
  ).describe("All endorsements found in the document")
6572
6576
  });
6573
6577
  function buildEndorsementsPrompt() {
6574
- return `You are an expert insurance document analyst. Extract ALL endorsements from this document. Preserve original language verbatim.
6578
+ return `You are an expert insurance document analyst. Build a compact source-backed endorsement index for this document. Do not reproduce full endorsement language in the JSON output.
6575
6579
 
6576
6580
  For EACH endorsement, extract:
6577
6581
  - formNumber: the form identifier (e.g. "CG 21 47") \u2014 REQUIRED
@@ -6583,7 +6587,9 @@ For EACH endorsement, extract:
6583
6587
  - namedParties: for each party, extract name, role (additional_insured, loss_payee, mortgage_holder, certificate_holder, waiver_beneficiary, designated_person, other), relationship, and scope
6584
6588
  - keyTerms: notable provisions or key terms
6585
6589
  - premiumImpact: additional premium or credit if shown
6586
- - content: full verbatim text \u2014 REQUIRED
6590
+ - excerpt: short identifying source excerpt, capped at 300 characters
6591
+ - sourceSpanIds: source span IDs from the provided SOURCE SPANS that ground this endorsement
6592
+ - content: legacy fallback only; omit/null when sourceSpanIds are available
6587
6593
  - pageStart: page number where endorsement begins \u2014 REQUIRED
6588
6594
  - pageEnd: page number where endorsement ends
6589
6595
 
@@ -6593,6 +6599,11 @@ PERSONAL LINES ENDORSEMENT RECOGNITION:
6593
6599
  - HO 17 XX series: mobilehome endorsements
6594
6600
  - DP 04 XX series: dwelling fire endorsements
6595
6601
 
6602
+ Critical rules:
6603
+ - Return compact metadata plus source references. The original endorsement wording lives in source spans.
6604
+ - Do not return full endorsement text in content when sourceSpanIds are available.
6605
+ - Prefer sourceSpanIds over generated prose for evidence.
6606
+
6596
6607
  Return JSON only.`;
6597
6608
  }
6598
6609
 
@@ -6839,7 +6850,10 @@ var SubsectionSchema2 = import_zod35.z.object({
6839
6850
  title: import_zod35.z.string().describe("Subsection title"),
6840
6851
  sectionNumber: import_zod35.z.string().optional().describe("Subsection number"),
6841
6852
  pageNumber: import_zod35.z.number().optional().describe("Page number"),
6842
- content: import_zod35.z.string().describe("Full verbatim text")
6853
+ excerpt: import_zod35.z.string().optional().describe("Short source excerpt, not full verbatim text"),
6854
+ content: import_zod35.z.string().optional().describe("Legacy fallback only; do not return full text when sourceSpanIds are available"),
6855
+ sourceSpanIds: import_zod35.z.array(import_zod35.z.string()).optional().describe("Source span IDs grounding this subsection"),
6856
+ sourceTextHash: import_zod35.z.string().optional().describe("Hash of the source text when available")
6843
6857
  });
6844
6858
  var SectionsSchema = import_zod35.z.object({
6845
6859
  sections: import_zod35.z.array(
@@ -6860,15 +6874,18 @@ var SectionsSchema = import_zod35.z.object({
6860
6874
  "regulatory",
6861
6875
  "other"
6862
6876
  ]).describe("Section type classification"),
6863
- content: import_zod35.z.string().describe("Full verbatim text of the section"),
6877
+ excerpt: import_zod35.z.string().optional().describe("Short source excerpt, not full verbatim text"),
6878
+ content: import_zod35.z.string().optional().describe("Legacy fallback only; do not return full text when sourceSpanIds are available"),
6864
6879
  pageStart: import_zod35.z.number().describe("Starting page number"),
6865
6880
  pageEnd: import_zod35.z.number().optional().describe("Ending page number"),
6881
+ sourceSpanIds: import_zod35.z.array(import_zod35.z.string()).optional().describe("Source span IDs grounding this section"),
6882
+ sourceTextHash: import_zod35.z.string().optional().describe("Hash of the source text when available"),
6866
6883
  subsections: import_zod35.z.array(SubsectionSchema2).optional().describe("Subsections within this section")
6867
6884
  })
6868
6885
  ).describe("All document sections")
6869
6886
  });
6870
6887
  function buildSectionsPrompt() {
6871
- return `You are an expert insurance document analyst. Extract ALL sections, clauses, endorsements, and schedules from this document. Preserve the original language verbatim \u2014 do not summarize or paraphrase.
6888
+ return `You are an expert insurance document analyst. Build a compact source-backed section index for this document. Do not reproduce full policy language in the JSON output.
6872
6889
 
6873
6890
  For each section, classify its type:
6874
6891
  - "declarations" \u2014 declarations page(s) listing named insured, policy period, limits, premiums
@@ -6882,10 +6899,13 @@ For each section, classify its type:
6882
6899
  - "notice", "regulatory" \u2014 notice provisions or regulatory disclosures
6883
6900
  - "other" \u2014 anything that doesn't fit the above categories
6884
6901
 
6885
- Include accurate page numbers for every section. Include subsections only if the section has clearly defined subsections with their own titles.
6902
+ Include accurate page numbers for every section. Include sourceSpanIds from the provided SOURCE SPANS whenever available. Include subsections only if the section has clearly defined subsections with their own titles.
6886
6903
  If a page begins or ends in the middle of a section, treat it as a continuation of the existing section instead of creating a new orphan section from the fragment.
6887
6904
 
6888
6905
  Critical rules:
6906
+ - Return compact metadata plus source references. The original policy wording lives in source spans.
6907
+ - Use excerpt only for a short identifying snippet, capped at 300 characters.
6908
+ - Do not return full section text in content when sourceSpanIds are available. Leave content omitted/null in source-backed mode.
6889
6909
  - Ignore table-of-contents entries, page-number references, repeating headers/footers, and other navigational artifacts.
6890
6910
  - Do not create a new section from a lone continuation fragment such as a single paragraph tail or list item that clearly belongs to the previous page's section.
6891
6911
  - When a section spans multiple pages, keep it as one section with pageStart/pageEnd covering the full span represented in this extraction.