@claritylabs/cl-sdk 1.2.1 → 1.3.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.mjs CHANGED
@@ -673,7 +673,8 @@ var EndorsementSchema = z5.object({
673
673
  namedParties: z5.array(EndorsementPartySchema).optional(),
674
674
  keyTerms: z5.array(z5.string()).optional(),
675
675
  premiumImpact: z5.string().optional(),
676
- content: z5.string(),
676
+ excerpt: z5.string().optional(),
677
+ content: z5.string().optional(),
677
678
  pageStart: z5.number(),
678
679
  pageEnd: z5.number().optional(),
679
680
  recordId: z5.string().optional(),
@@ -1286,7 +1287,10 @@ var SubsectionSchema = z16.object({
1286
1287
  title: z16.string(),
1287
1288
  sectionNumber: z16.string().optional(),
1288
1289
  pageNumber: z16.number().optional(),
1289
- content: z16.string()
1290
+ excerpt: z16.string().optional(),
1291
+ content: z16.string().optional(),
1292
+ sourceSpanIds: z16.array(z16.string()).optional(),
1293
+ sourceTextHash: z16.string().optional()
1290
1294
  });
1291
1295
  var SectionSchema = z16.object({
1292
1296
  title: z16.string(),
@@ -1295,7 +1299,8 @@ var SectionSchema = z16.object({
1295
1299
  pageEnd: z16.number().optional(),
1296
1300
  type: z16.string(),
1297
1301
  coverageType: z16.string().optional(),
1298
- content: z16.string(),
1302
+ excerpt: z16.string().optional(),
1303
+ content: z16.string().optional(),
1299
1304
  subsections: z16.array(SubsectionSchema).optional(),
1300
1305
  recordId: z16.string().optional(),
1301
1306
  sourceSpanIds: z16.array(z16.string()).optional(),
@@ -2813,6 +2818,14 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
2813
2818
  maxTokens,
2814
2819
  taskKind,
2815
2820
  budgetDiagnostics,
2821
+ trace: {
2822
+ label: `${name} pages ${startPage}-${endPage}`,
2823
+ extractorName: name,
2824
+ startPage,
2825
+ endPage,
2826
+ phase: "extractor",
2827
+ sourceBacked: !!sourceContext
2828
+ },
2816
2829
  providerOptions: extractorProviderOptions
2817
2830
  })
2818
2831
  );
@@ -3678,21 +3691,30 @@ function collectContentFields(doc) {
3678
3691
  entries.push({ id: id++, path, text });
3679
3692
  }
3680
3693
  }
3694
+ function hasSourceBacking(record) {
3695
+ return Array.isArray(record.sourceSpanIds) && record.sourceSpanIds.length > 0 || !!record.sourceTextHash;
3696
+ }
3681
3697
  add("summary", doc.summary);
3682
3698
  if (doc.sections) {
3683
3699
  for (let i = 0; i < doc.sections.length; i++) {
3684
3700
  const s = doc.sections[i];
3685
- add(`sections[${i}].content`, s.content);
3701
+ if (!hasSourceBacking(s)) {
3702
+ add(`sections[${i}].content`, s.content);
3703
+ }
3686
3704
  if (s.subsections) {
3687
3705
  for (let j = 0; j < s.subsections.length; j++) {
3688
- add(`sections[${i}].subsections[${j}].content`, s.subsections[j].content);
3706
+ if (!hasSourceBacking(s.subsections[j])) {
3707
+ add(`sections[${i}].subsections[${j}].content`, s.subsections[j].content);
3708
+ }
3689
3709
  }
3690
3710
  }
3691
3711
  }
3692
3712
  }
3693
3713
  if (doc.endorsements) {
3694
3714
  for (let i = 0; i < doc.endorsements.length; i++) {
3695
- add(`endorsements[${i}].content`, doc.endorsements[i].content);
3715
+ if (!hasSourceBacking(doc.endorsements[i])) {
3716
+ add(`endorsements[${i}].content`, doc.endorsements[i].content);
3717
+ }
3696
3718
  }
3697
3719
  }
3698
3720
  if (doc.exclusions) {
@@ -3794,6 +3816,12 @@ async function formatDocumentContent(doc, generateText, options) {
3794
3816
  maxTokens: options?.maxTokens ?? 16384,
3795
3817
  taskKind: options?.taskKind,
3796
3818
  budgetDiagnostics: options?.budgetDiagnostics,
3819
+ trace: {
3820
+ label: `format content batch ${batchIdx + 1}/${batches.length}`,
3821
+ phase: "format",
3822
+ batchIndex: batchIdx + 1,
3823
+ batchCount: batches.length
3824
+ },
3797
3825
  providerOptions: options?.providerOptions
3798
3826
  })
3799
3827
  );
@@ -3868,7 +3896,7 @@ function chunkDocument(doc) {
3868
3896
  documentId: docId,
3869
3897
  type,
3870
3898
  text,
3871
- metadata: stringMetadata(metadata)
3899
+ metadata: stringMetadata({ evidenceKind: "structured_fact", ...metadata })
3872
3900
  });
3873
3901
  }
3874
3902
  pushChunk(
@@ -4147,16 +4175,29 @@ function chunkDocument(doc) {
4147
4175
  );
4148
4176
  });
4149
4177
  doc.endorsements?.forEach((end, i) => {
4178
+ const text = lines([
4179
+ `Endorsement: ${end.title}`,
4180
+ end.formNumber ? `Form: ${end.formNumber}` : null,
4181
+ end.editionDate ? `Edition: ${end.editionDate}` : null,
4182
+ `Type: ${end.endorsementType}`,
4183
+ end.effectiveDate ? `Effective Date: ${end.effectiveDate}` : null,
4184
+ end.affectedCoverageParts?.length ? `Affected Coverage Parts: ${end.affectedCoverageParts.join(", ")}` : null,
4185
+ end.keyTerms?.length ? `Key Terms: ${end.keyTerms.join("; ")}` : null,
4186
+ end.premiumImpact ? `Premium Impact: ${end.premiumImpact}` : null,
4187
+ end.excerpt ? `Excerpt: ${end.excerpt}` : null
4188
+ ]);
4189
+ if (!text.trim()) return;
4150
4190
  pushChunk(
4151
4191
  `endorsement:${i}`,
4152
4192
  "endorsement",
4153
- `Endorsement: ${end.title}
4154
- ${end.content}`.trim(),
4193
+ text,
4155
4194
  {
4156
4195
  endorsementType: end.endorsementType,
4157
4196
  formNumber: end.formNumber,
4158
4197
  pageStart: end.pageStart,
4159
4198
  pageEnd: end.pageEnd,
4199
+ sourceSpanIds: end.sourceSpanIds?.join(","),
4200
+ sourceTextHash: end.sourceTextHash,
4160
4201
  documentType: doc.type
4161
4202
  }
4162
4203
  );
@@ -4278,93 +4319,51 @@ ${declLines.join("\n")}`, declMeta);
4278
4319
  }
4279
4320
  doc.sections?.forEach((sec, i) => {
4280
4321
  const hasSubsections = sec.subsections && sec.subsections.length > 0;
4281
- const contentLength = sec.content.length;
4282
- if (hasSubsections) {
4283
- pushChunk(
4284
- `section:${i}`,
4285
- "section",
4286
- `Section: ${sec.title}
4287
- ${sec.content}`,
4288
- {
4289
- sectionType: sec.type,
4290
- sectionNumber: sec.sectionNumber,
4291
- pageStart: sec.pageStart,
4292
- pageEnd: sec.pageEnd,
4293
- documentType: doc.type,
4294
- hasSubsections: "true"
4295
- }
4296
- );
4297
- sec.subsections.forEach((sub, j) => {
4298
- pushChunk(
4299
- `section:${i}:sub:${j}`,
4300
- "section",
4301
- `${sec.title} > ${sub.title}
4302
- ${sub.content}`,
4303
- {
4304
- sectionType: sec.type,
4305
- parentSection: sec.title,
4306
- sectionNumber: sub.sectionNumber,
4307
- pageNumber: sub.pageNumber,
4308
- documentType: doc.type
4309
- }
4310
- );
4311
- });
4312
- } else if (contentLength > 2e3) {
4313
- const paragraphs = sec.content.split(/\n\n+/);
4314
- let currentChunk = "";
4315
- let chunkIndex = 0;
4316
- for (const para of paragraphs) {
4317
- if (currentChunk.length + para.length > 1e3 && currentChunk.length > 0) {
4318
- pushChunk(
4319
- `section:${i}:part:${chunkIndex}`,
4320
- "section",
4321
- `Section: ${sec.title} (part ${chunkIndex + 1})
4322
- ${currentChunk.trim()}`,
4323
- {
4324
- sectionType: sec.type,
4325
- sectionNumber: sec.sectionNumber,
4326
- pageStart: sec.pageStart,
4327
- pageEnd: sec.pageEnd,
4328
- documentType: doc.type,
4329
- partIndex: chunkIndex
4330
- }
4331
- );
4332
- currentChunk = "";
4333
- chunkIndex++;
4334
- }
4335
- currentChunk += (currentChunk ? "\n\n" : "") + para;
4336
- }
4337
- if (currentChunk.trim()) {
4338
- pushChunk(
4339
- `section:${i}:part:${chunkIndex}`,
4340
- "section",
4341
- `Section: ${sec.title} (part ${chunkIndex + 1})
4342
- ${currentChunk.trim()}`,
4343
- {
4344
- sectionType: sec.type,
4345
- sectionNumber: sec.sectionNumber,
4346
- pageStart: sec.pageStart,
4347
- pageEnd: sec.pageEnd,
4348
- documentType: doc.type,
4349
- partIndex: chunkIndex
4350
- }
4351
- );
4322
+ pushChunk(
4323
+ `section:${i}`,
4324
+ "section",
4325
+ lines([
4326
+ `Section: ${sec.title}`,
4327
+ `Type: ${sec.type}`,
4328
+ sec.sectionNumber ? `Section Number: ${sec.sectionNumber}` : null,
4329
+ `Pages: ${sec.pageStart}${sec.pageEnd ? `-${sec.pageEnd}` : ""}`,
4330
+ sec.excerpt ? `Excerpt: ${sec.excerpt}` : null,
4331
+ hasSubsections ? `Subsections: ${sec.subsections.map((sub) => sub.title).join(", ")}` : null
4332
+ ]),
4333
+ {
4334
+ evidenceKind: "navigation",
4335
+ sectionType: sec.type,
4336
+ sectionNumber: sec.sectionNumber,
4337
+ pageStart: sec.pageStart,
4338
+ pageEnd: sec.pageEnd,
4339
+ sourceSpanIds: sec.sourceSpanIds?.join(","),
4340
+ sourceTextHash: sec.sourceTextHash,
4341
+ documentType: doc.type,
4342
+ hasSubsections
4352
4343
  }
4353
- } else {
4344
+ );
4345
+ sec.subsections?.forEach((sub, j) => {
4354
4346
  pushChunk(
4355
- `section:${i}`,
4347
+ `section:${i}:sub:${j}`,
4356
4348
  "section",
4357
- `Section: ${sec.title}
4358
- ${sec.content}`,
4349
+ lines([
4350
+ `Section: ${sec.title} > ${sub.title}`,
4351
+ sub.sectionNumber ? `Section Number: ${sub.sectionNumber}` : null,
4352
+ sub.pageNumber ? `Page: ${sub.pageNumber}` : null,
4353
+ sub.excerpt ? `Excerpt: ${sub.excerpt}` : null
4354
+ ]),
4359
4355
  {
4356
+ evidenceKind: "navigation",
4360
4357
  sectionType: sec.type,
4361
- sectionNumber: sec.sectionNumber,
4362
- pageStart: sec.pageStart,
4363
- pageEnd: sec.pageEnd,
4358
+ parentSection: sec.title,
4359
+ sectionNumber: sub.sectionNumber,
4360
+ pageNumber: sub.pageNumber,
4361
+ sourceSpanIds: sub.sourceSpanIds?.join(","),
4362
+ sourceTextHash: sub.sourceTextHash,
4364
4363
  documentType: doc.type
4365
4364
  }
4366
4365
  );
4367
- }
4366
+ });
4368
4367
  });
4369
4368
  doc.locations?.forEach((loc, i) => {
4370
4369
  chunks.push({
@@ -6236,14 +6235,17 @@ var EndorsementsSchema = z29.object({
6236
6235
  ).optional().describe("Named parties (additional insureds, loss payees, etc.)"),
6237
6236
  keyTerms: z29.array(z29.string()).optional().describe("Key terms or notable provisions in the endorsement"),
6238
6237
  premiumImpact: z29.string().optional().describe("Additional premium or credit"),
6239
- content: z29.string().describe("Full verbatim text of the endorsement"),
6238
+ excerpt: z29.string().optional().describe("Short source excerpt, not full verbatim text"),
6239
+ content: z29.string().optional().describe("Legacy fallback only; do not return full text when sourceSpanIds are available"),
6240
6240
  pageStart: z29.number().describe("Starting page number of this endorsement"),
6241
- pageEnd: z29.number().optional().describe("Ending page number of this endorsement")
6241
+ pageEnd: z29.number().optional().describe("Ending page number of this endorsement"),
6242
+ sourceSpanIds: z29.array(z29.string()).optional().describe("Source span IDs grounding this endorsement"),
6243
+ sourceTextHash: z29.string().optional().describe("Hash of the source text when available")
6242
6244
  })
6243
6245
  ).describe("All endorsements found in the document")
6244
6246
  });
6245
6247
  function buildEndorsementsPrompt() {
6246
- return `You are an expert insurance document analyst. Extract ALL endorsements from this document. Preserve original language verbatim.
6248
+ 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.
6247
6249
 
6248
6250
  For EACH endorsement, extract:
6249
6251
  - formNumber: the form identifier (e.g. "CG 21 47") \u2014 REQUIRED
@@ -6255,7 +6257,9 @@ For EACH endorsement, extract:
6255
6257
  - namedParties: for each party, extract name, role (additional_insured, loss_payee, mortgage_holder, certificate_holder, waiver_beneficiary, designated_person, other), relationship, and scope
6256
6258
  - keyTerms: notable provisions or key terms
6257
6259
  - premiumImpact: additional premium or credit if shown
6258
- - content: full verbatim text \u2014 REQUIRED
6260
+ - excerpt: short identifying source excerpt, capped at 300 characters
6261
+ - sourceSpanIds: source span IDs from the provided SOURCE SPANS that ground this endorsement
6262
+ - content: legacy fallback only; omit/null when sourceSpanIds are available
6259
6263
  - pageStart: page number where endorsement begins \u2014 REQUIRED
6260
6264
  - pageEnd: page number where endorsement ends
6261
6265
 
@@ -6265,6 +6269,11 @@ PERSONAL LINES ENDORSEMENT RECOGNITION:
6265
6269
  - HO 17 XX series: mobilehome endorsements
6266
6270
  - DP 04 XX series: dwelling fire endorsements
6267
6271
 
6272
+ Critical rules:
6273
+ - Return compact metadata plus source references. The original endorsement wording lives in source spans.
6274
+ - Do not return full endorsement text in content when sourceSpanIds are available.
6275
+ - Prefer sourceSpanIds over generated prose for evidence.
6276
+
6268
6277
  Return JSON only.`;
6269
6278
  }
6270
6279
 
@@ -6511,7 +6520,10 @@ var SubsectionSchema2 = z35.object({
6511
6520
  title: z35.string().describe("Subsection title"),
6512
6521
  sectionNumber: z35.string().optional().describe("Subsection number"),
6513
6522
  pageNumber: z35.number().optional().describe("Page number"),
6514
- content: z35.string().describe("Full verbatim text")
6523
+ excerpt: z35.string().optional().describe("Short source excerpt, not full verbatim text"),
6524
+ content: z35.string().optional().describe("Legacy fallback only; do not return full text when sourceSpanIds are available"),
6525
+ sourceSpanIds: z35.array(z35.string()).optional().describe("Source span IDs grounding this subsection"),
6526
+ sourceTextHash: z35.string().optional().describe("Hash of the source text when available")
6515
6527
  });
6516
6528
  var SectionsSchema = z35.object({
6517
6529
  sections: z35.array(
@@ -6532,15 +6544,18 @@ var SectionsSchema = z35.object({
6532
6544
  "regulatory",
6533
6545
  "other"
6534
6546
  ]).describe("Section type classification"),
6535
- content: z35.string().describe("Full verbatim text of the section"),
6547
+ excerpt: z35.string().optional().describe("Short source excerpt, not full verbatim text"),
6548
+ content: z35.string().optional().describe("Legacy fallback only; do not return full text when sourceSpanIds are available"),
6536
6549
  pageStart: z35.number().describe("Starting page number"),
6537
6550
  pageEnd: z35.number().optional().describe("Ending page number"),
6551
+ sourceSpanIds: z35.array(z35.string()).optional().describe("Source span IDs grounding this section"),
6552
+ sourceTextHash: z35.string().optional().describe("Hash of the source text when available"),
6538
6553
  subsections: z35.array(SubsectionSchema2).optional().describe("Subsections within this section")
6539
6554
  })
6540
6555
  ).describe("All document sections")
6541
6556
  });
6542
6557
  function buildSectionsPrompt() {
6543
- 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.
6558
+ 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.
6544
6559
 
6545
6560
  For each section, classify its type:
6546
6561
  - "declarations" \u2014 declarations page(s) listing named insured, policy period, limits, premiums
@@ -6554,10 +6569,13 @@ For each section, classify its type:
6554
6569
  - "notice", "regulatory" \u2014 notice provisions or regulatory disclosures
6555
6570
  - "other" \u2014 anything that doesn't fit the above categories
6556
6571
 
6557
- Include accurate page numbers for every section. Include subsections only if the section has clearly defined subsections with their own titles.
6572
+ 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.
6558
6573
  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.
6559
6574
 
6560
6575
  Critical rules:
6576
+ - Return compact metadata plus source references. The original policy wording lives in source spans.
6577
+ - Use excerpt only for a short identifying snippet, capped at 300 characters.
6578
+ - Do not return full section text in content when sourceSpanIds are available. Leave content omitted/null in source-backed mode.
6561
6579
  - Ignore table-of-contents entries, page-number references, repeating headers/footers, and other navigational artifacts.
6562
6580
  - 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.
6563
6581
  - When a section spans multiple pages, keep it as one section with pageStart/pageEnd covering the full span represented in this extraction.