@claritylabs/cl-sdk 1.3.8 → 2.0.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
@@ -567,14 +567,20 @@ var FormReferenceSchema = z3.object({
567
567
  title: z3.string().optional(),
568
568
  formType: z3.enum(["coverage", "endorsement", "declarations", "application", "notice", "other"]),
569
569
  pageStart: z3.number().optional(),
570
- pageEnd: z3.number().optional()
570
+ pageEnd: z3.number().optional(),
571
+ documentNodeId: z3.string().optional(),
572
+ sourceSpanIds: z3.array(z3.string()).optional(),
573
+ sourceTextHash: z3.string().optional()
571
574
  });
572
575
  var TaxFeeItemSchema = z3.object({
573
576
  name: z3.string(),
574
577
  amount: z3.string(),
575
578
  amountValue: z3.number().optional(),
576
579
  type: z3.enum(["tax", "fee", "surcharge", "assessment"]).optional(),
577
- description: z3.string().optional()
580
+ description: z3.string().optional(),
581
+ documentNodeId: z3.string().optional(),
582
+ sourceSpanIds: z3.array(z3.string()).optional(),
583
+ sourceTextHash: z3.string().optional()
578
584
  });
579
585
  var RatingBasisSchema = z3.object({
580
586
  type: RatingBasisTypeSchema,
@@ -630,6 +636,7 @@ var CoverageSchema = z4.object({
630
636
  sectionRef: z4.string().optional(),
631
637
  originalContent: z4.string().optional(),
632
638
  recordId: z4.string().optional(),
639
+ documentNodeId: z4.string().optional(),
633
640
  sourceSpanIds: z4.array(z4.string()).optional(),
634
641
  sourceTextHash: z4.string().optional()
635
642
  });
@@ -659,6 +666,7 @@ var EnrichedCoverageSchema = z4.object({
659
666
  sectionRef: z4.string().optional(),
660
667
  originalContent: z4.string().optional(),
661
668
  recordId: z4.string().optional(),
669
+ documentNodeId: z4.string().optional(),
662
670
  sourceSpanIds: z4.array(z4.string()).optional(),
663
671
  sourceTextHash: z4.string().optional()
664
672
  });
@@ -687,6 +695,7 @@ var EndorsementSchema = z5.object({
687
695
  pageStart: z5.number(),
688
696
  pageEnd: z5.number().optional(),
689
697
  recordId: z5.string().optional(),
698
+ documentNodeId: z5.string().optional(),
690
699
  sourceSpanIds: z5.array(z5.string()).optional(),
691
700
  sourceTextHash: z5.string().optional()
692
701
  });
@@ -705,6 +714,7 @@ var ExclusionSchema = z6.object({
705
714
  content: z6.string(),
706
715
  pageNumber: z6.number().optional(),
707
716
  recordId: z6.string().optional(),
717
+ documentNodeId: z6.string().optional(),
708
718
  sourceSpanIds: z6.array(z6.string()).optional(),
709
719
  sourceTextHash: z6.string().optional()
710
720
  });
@@ -722,6 +732,7 @@ var PolicyConditionSchema = z7.object({
722
732
  keyValues: z7.array(ConditionKeyValueSchema).optional(),
723
733
  pageNumber: z7.number().optional(),
724
734
  recordId: z7.string().optional(),
735
+ documentNodeId: z7.string().optional(),
725
736
  sourceSpanIds: z7.array(z7.string()).optional(),
726
737
  sourceTextHash: z7.string().optional()
727
738
  });
@@ -1298,6 +1309,7 @@ var SubsectionSchema = z16.object({
1298
1309
  pageNumber: z16.number().optional(),
1299
1310
  excerpt: z16.string().optional(),
1300
1311
  content: z16.string().optional(),
1312
+ documentNodeId: z16.string().optional(),
1301
1313
  sourceSpanIds: z16.array(z16.string()).optional(),
1302
1314
  sourceTextHash: z16.string().optional()
1303
1315
  });
@@ -1312,6 +1324,7 @@ var SectionSchema = z16.object({
1312
1324
  content: z16.string().optional(),
1313
1325
  subsections: z16.array(SubsectionSchema).optional(),
1314
1326
  recordId: z16.string().optional(),
1327
+ documentNodeId: z16.string().optional(),
1315
1328
  sourceSpanIds: z16.array(z16.string()).optional(),
1316
1329
  sourceTextHash: z16.string().optional()
1317
1330
  });
@@ -1325,13 +1338,19 @@ var UnderwritingConditionSchema = z16.object({
1325
1338
  var PremiumLineSchema = z16.object({
1326
1339
  line: z16.string(),
1327
1340
  amount: z16.string(),
1328
- amountValue: z16.number().optional()
1341
+ amountValue: z16.number().optional(),
1342
+ documentNodeId: z16.string().optional(),
1343
+ sourceSpanIds: z16.array(z16.string()).optional(),
1344
+ sourceTextHash: z16.string().optional()
1329
1345
  });
1330
1346
  var AuxiliaryFactSchema = z16.object({
1331
1347
  key: z16.string(),
1332
1348
  value: z16.string(),
1333
1349
  subject: z16.string().optional(),
1334
- context: z16.string().optional()
1350
+ context: z16.string().optional(),
1351
+ documentNodeId: z16.string().optional(),
1352
+ sourceSpanIds: z16.array(z16.string()).optional(),
1353
+ sourceTextHash: z16.string().optional()
1335
1354
  });
1336
1355
  var DefinitionSchema = z16.object({
1337
1356
  term: z16.string(),
@@ -1342,6 +1361,7 @@ var DefinitionSchema = z16.object({
1342
1361
  sectionRef: z16.string().optional(),
1343
1362
  originalContent: z16.string().optional(),
1344
1363
  recordId: z16.string().optional(),
1364
+ documentNodeId: z16.string().optional(),
1345
1365
  sourceSpanIds: z16.array(z16.string()).optional(),
1346
1366
  sourceTextHash: z16.string().optional()
1347
1367
  });
@@ -1359,9 +1379,60 @@ var CoveredReasonSchema = z16.object({
1359
1379
  sectionRef: z16.string().optional(),
1360
1380
  originalContent: z16.string().optional(),
1361
1381
  recordId: z16.string().optional(),
1382
+ documentNodeId: z16.string().optional(),
1362
1383
  sourceSpanIds: z16.array(z16.string()).optional(),
1363
1384
  sourceTextHash: z16.string().optional()
1364
1385
  });
1386
+ var DocumentTableOfContentsEntrySchema = z16.object({
1387
+ title: z16.string(),
1388
+ level: z16.number().int().positive().optional(),
1389
+ pageStart: z16.number().optional(),
1390
+ pageEnd: z16.number().optional(),
1391
+ documentNodeId: z16.string().optional(),
1392
+ sourceSpanIds: z16.array(z16.string()).optional()
1393
+ });
1394
+ var DocumentPageMapEntrySchema = z16.object({
1395
+ page: z16.number().int().positive(),
1396
+ label: z16.string().optional(),
1397
+ formNumber: z16.string().optional(),
1398
+ formTitle: z16.string().optional(),
1399
+ sectionTitle: z16.string().optional(),
1400
+ extractorNames: z16.array(z16.string()).optional(),
1401
+ sourceSpanIds: z16.array(z16.string()).optional()
1402
+ });
1403
+ var DocumentAgentGuidanceSchema = z16.object({
1404
+ kind: z16.string(),
1405
+ title: z16.string(),
1406
+ detail: z16.string(),
1407
+ sourceSpanIds: z16.array(z16.string()).optional()
1408
+ });
1409
+ var DocumentMetadataSchema = z16.object({
1410
+ formInventory: z16.array(FormReferenceSchema).optional(),
1411
+ tableOfContents: z16.array(DocumentTableOfContentsEntrySchema).optional(),
1412
+ pageMap: z16.array(DocumentPageMapEntrySchema).optional(),
1413
+ agentGuidance: z16.array(DocumentAgentGuidanceSchema).optional()
1414
+ });
1415
+ var DocumentNodeSchema = z16.lazy(
1416
+ () => z16.object({
1417
+ id: z16.string(),
1418
+ title: z16.string(),
1419
+ originalTitle: z16.string().optional(),
1420
+ type: z16.string().optional(),
1421
+ label: z16.string().optional(),
1422
+ level: z16.number().int().positive().optional(),
1423
+ sectionNumber: z16.string().optional(),
1424
+ pageStart: z16.number().optional(),
1425
+ pageEnd: z16.number().optional(),
1426
+ formNumber: z16.string().optional(),
1427
+ formTitle: z16.string().optional(),
1428
+ excerpt: z16.string().optional(),
1429
+ content: z16.string().optional(),
1430
+ interpretationLabels: z16.array(z16.string()).optional(),
1431
+ sourceSpanIds: z16.array(z16.string()).optional(),
1432
+ sourceTextHash: z16.string().optional(),
1433
+ children: z16.array(DocumentNodeSchema).optional()
1434
+ })
1435
+ );
1365
1436
  var BaseDocumentFields = {
1366
1437
  id: z16.string(),
1367
1438
  carrier: z16.string(),
@@ -1372,6 +1443,8 @@ var BaseDocumentFields = {
1372
1443
  summary: z16.string().optional(),
1373
1444
  policyTypes: z16.array(z16.string()).optional(),
1374
1445
  coverages: z16.array(CoverageSchema),
1446
+ documentMetadata: DocumentMetadataSchema,
1447
+ documentOutline: z16.array(DocumentNodeSchema),
1375
1448
  sections: z16.array(SectionSchema).optional(),
1376
1449
  definitions: z16.array(DefinitionSchema).optional(),
1377
1450
  coveredReasons: z16.array(CoveredReasonSchema).optional(),
@@ -3279,6 +3352,8 @@ function assembleDocument(documentId, documentType, memory) {
3279
3352
  carrier: readRecordValue(carrier, "carrierName") ?? "Unknown",
3280
3353
  insuredName: readRecordValue(insured, "insuredName") ?? "Unknown",
3281
3354
  coverages: coverageRecords,
3355
+ documentMetadata: {},
3356
+ documentOutline: [],
3282
3357
  policyTypes: readRecordValue(classify, "policyTypes"),
3283
3358
  ...sanitizeNulls(carrier ?? {}),
3284
3359
  ...sanitizeNulls(insured ?? {}),
@@ -3330,6 +3405,247 @@ function assembleDocument(documentId, documentType, memory) {
3330
3405
  return doc;
3331
3406
  }
3332
3407
 
3408
+ // src/extraction/document-structure.ts
3409
+ var FACT_ARRAY_PATHS = [
3410
+ "coverages",
3411
+ "enrichedCoverages",
3412
+ "endorsements",
3413
+ "exclusions",
3414
+ "conditions",
3415
+ "definitions",
3416
+ "coveredReasons",
3417
+ "taxesAndFees",
3418
+ "premiumBreakdown",
3419
+ "supplementaryFacts"
3420
+ ];
3421
+ function slugPart(value) {
3422
+ const text = String(value ?? "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
3423
+ return text || "node";
3424
+ }
3425
+ function numberValue(record, ...keys) {
3426
+ for (const key of keys) {
3427
+ const value = record[key];
3428
+ if (typeof value === "number" && Number.isFinite(value)) return value;
3429
+ }
3430
+ return void 0;
3431
+ }
3432
+ function stringValue2(record, ...keys) {
3433
+ for (const key of keys) {
3434
+ const value = record[key];
3435
+ if (typeof value === "string" && value.trim()) return value.trim();
3436
+ }
3437
+ return void 0;
3438
+ }
3439
+ function stringArray(value) {
3440
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string" && item.length > 0) : [];
3441
+ }
3442
+ function sourceUnit3(span) {
3443
+ return span.sourceUnit ?? span.metadata?.sourceUnit;
3444
+ }
3445
+ function spanPage(span) {
3446
+ return span.pageStart ?? span.location?.page ?? span.location?.startPage;
3447
+ }
3448
+ function spanPageEnd(span) {
3449
+ return span.pageEnd ?? span.location?.endPage ?? spanPage(span);
3450
+ }
3451
+ function sourceSpansForPage(sourceSpans, page) {
3452
+ return sourceSpans.filter((span) => spanPage(span) === page && sourceUnit3(span) === "page").map((span) => span.id);
3453
+ }
3454
+ function nodePageOverlaps(node, record) {
3455
+ const recordStart = numberValue(record, "pageNumber", "pageStart", "resolvedFromPage");
3456
+ const recordEnd = numberValue(record, "pageNumber", "pageEnd", "resolvedFromPage") ?? recordStart;
3457
+ if (!recordStart) return false;
3458
+ const nodeStart = node.pageStart ?? node.pageEnd;
3459
+ const nodeEnd = node.pageEnd ?? node.pageStart;
3460
+ if (!nodeStart) return false;
3461
+ return recordStart <= (nodeEnd ?? nodeStart) && (recordEnd ?? recordStart) >= nodeStart;
3462
+ }
3463
+ function nodeFormMatches(node, record) {
3464
+ const formNumber = stringValue2(record, "formNumber");
3465
+ return Boolean(formNumber && node.formNumber && formNumber.toLowerCase() === node.formNumber.toLowerCase());
3466
+ }
3467
+ function nodeSourceOverlaps(node, record) {
3468
+ const nodeSourceIds = new Set(node.sourceSpanIds ?? []);
3469
+ if (nodeSourceIds.size === 0) return false;
3470
+ return stringArray(record.sourceSpanIds).some((id) => nodeSourceIds.has(id));
3471
+ }
3472
+ function findBestNode(nodes, record) {
3473
+ let best;
3474
+ const visit = (node) => {
3475
+ let score = 0;
3476
+ if (nodeSourceOverlaps(node, record)) score += 8;
3477
+ if (nodeFormMatches(node, record)) score += 4;
3478
+ if (nodePageOverlaps(node, record)) score += 3;
3479
+ if (score > 0 && (!best || score > best.score)) {
3480
+ best = { node, score };
3481
+ }
3482
+ for (const child of node.children ?? []) visit(child);
3483
+ };
3484
+ for (const node of nodes) visit(node);
3485
+ return best?.node;
3486
+ }
3487
+ function attachDocumentNodeIds(document, nodes) {
3488
+ const doc = document;
3489
+ for (const path of FACT_ARRAY_PATHS) {
3490
+ const value = doc[path];
3491
+ if (!Array.isArray(value)) continue;
3492
+ doc[path] = value.map((item) => {
3493
+ if (!item || typeof item !== "object" || Array.isArray(item)) return item;
3494
+ const record = item;
3495
+ if (typeof record.documentNodeId === "string" && record.documentNodeId.length > 0) return record;
3496
+ const node = findBestNode(nodes, record);
3497
+ return node ? { ...record, documentNodeId: node.id } : record;
3498
+ });
3499
+ }
3500
+ }
3501
+ function buildNodeFromSection(section, index) {
3502
+ const title = stringValue2(section, "title", "name", "sectionRef") ?? `Section ${index + 1}`;
3503
+ const id = stringValue2(section, "documentNodeId", "recordId") ?? `section:${index}:${slugPart(title)}`;
3504
+ const pageStart = numberValue(section, "pageStart", "pageNumber");
3505
+ const pageEnd = numberValue(section, "pageEnd", "pageNumber") ?? pageStart;
3506
+ const type = stringValue2(section, "type");
3507
+ const coverageType = stringValue2(section, "coverageType");
3508
+ const sourceSpanIds = stringArray(section.sourceSpanIds);
3509
+ const children = Array.isArray(section.subsections) ? section.subsections.filter((item) => Boolean(item) && typeof item === "object" && !Array.isArray(item)).map((subsection, childIndex) => {
3510
+ const childTitle = stringValue2(subsection, "title", "name") ?? `${title} ${childIndex + 1}`;
3511
+ const childId = stringValue2(subsection, "documentNodeId", "recordId") ?? `${id}:subsection:${childIndex}:${slugPart(childTitle)}`;
3512
+ return {
3513
+ id: childId,
3514
+ title: childTitle,
3515
+ originalTitle: childTitle,
3516
+ type,
3517
+ label: type,
3518
+ level: 2,
3519
+ sectionNumber: stringValue2(subsection, "sectionNumber"),
3520
+ pageStart: numberValue(subsection, "pageNumber") ?? pageStart,
3521
+ pageEnd: numberValue(subsection, "pageNumber") ?? pageStart,
3522
+ excerpt: stringValue2(subsection, "excerpt"),
3523
+ content: stringValue2(subsection, "content"),
3524
+ sourceSpanIds: stringArray(subsection.sourceSpanIds),
3525
+ sourceTextHash: stringValue2(subsection, "sourceTextHash")
3526
+ };
3527
+ }) : void 0;
3528
+ return {
3529
+ id,
3530
+ title,
3531
+ originalTitle: title,
3532
+ type,
3533
+ label: type,
3534
+ level: 1,
3535
+ sectionNumber: stringValue2(section, "sectionNumber"),
3536
+ pageStart,
3537
+ pageEnd,
3538
+ formNumber: stringValue2(section, "formNumber"),
3539
+ formTitle: stringValue2(section, "formTitle"),
3540
+ excerpt: stringValue2(section, "excerpt"),
3541
+ content: stringValue2(section, "content"),
3542
+ interpretationLabels: [type, coverageType].filter((value) => Boolean(value)),
3543
+ sourceSpanIds: sourceSpanIds.length > 0 ? sourceSpanIds : void 0,
3544
+ sourceTextHash: stringValue2(section, "sourceTextHash"),
3545
+ children: children && children.length > 0 ? children : void 0
3546
+ };
3547
+ }
3548
+ function buildNodesFromSourceSpans(sourceSpans) {
3549
+ const candidates = sourceSpans.filter((span) => {
3550
+ const unit = sourceUnit3(span);
3551
+ return unit === "section" || unit === "section_candidate" || unit === "page";
3552
+ });
3553
+ return candidates.sort((left, right) => (spanPage(left) ?? 0) - (spanPage(right) ?? 0) || left.id.localeCompare(right.id)).map((span, index) => {
3554
+ const title = span.sectionId ?? span.formNumber ?? (sourceUnit3(span) === "page" && spanPage(span) ? `Page ${spanPage(span)}` : `Source unit ${index + 1}`);
3555
+ return {
3556
+ id: `source:${index}:${slugPart(span.id)}`,
3557
+ title,
3558
+ originalTitle: title,
3559
+ type: sourceUnit3(span),
3560
+ label: sourceUnit3(span),
3561
+ level: 1,
3562
+ pageStart: spanPage(span),
3563
+ pageEnd: spanPageEnd(span),
3564
+ formNumber: span.formNumber,
3565
+ excerpt: span.text.slice(0, 500),
3566
+ sourceSpanIds: [span.id],
3567
+ sourceTextHash: span.textHash ?? span.hash
3568
+ };
3569
+ });
3570
+ }
3571
+ function flattenToc(nodes) {
3572
+ const entries = [];
3573
+ const visit = (node) => {
3574
+ entries.push({
3575
+ title: node.title,
3576
+ level: node.level,
3577
+ pageStart: node.pageStart,
3578
+ pageEnd: node.pageEnd,
3579
+ documentNodeId: node.id,
3580
+ sourceSpanIds: node.sourceSpanIds
3581
+ });
3582
+ for (const child of node.children ?? []) visit(child);
3583
+ };
3584
+ for (const node of nodes) visit(node);
3585
+ return entries;
3586
+ }
3587
+ function buildPageMap(pageAssignments, sourceSpans, document) {
3588
+ const forms = document.formInventory ?? [];
3589
+ return pageAssignments.sort((left, right) => left.localPageNumber - right.localPageNumber).map((assignment) => {
3590
+ const form = forms.find((item) => {
3591
+ const start = item.pageStart;
3592
+ const end = item.pageEnd ?? start;
3593
+ return start != null && end != null && assignment.localPageNumber >= start && assignment.localPageNumber <= end;
3594
+ });
3595
+ return {
3596
+ page: assignment.localPageNumber,
3597
+ label: assignment.notes,
3598
+ formNumber: form?.formNumber,
3599
+ formTitle: form?.title,
3600
+ extractorNames: assignment.extractorNames,
3601
+ sourceSpanIds: sourceSpansForPage(sourceSpans, assignment.localPageNumber)
3602
+ };
3603
+ });
3604
+ }
3605
+ function buildAgentGuidance(document) {
3606
+ const guidance = [
3607
+ {
3608
+ kind: "source_structure",
3609
+ title: "Use the source outline as navigation",
3610
+ detail: "The documentOutline preserves source order and page ranges. Treat interpretation labels as hints, not as a replacement for the source document structure."
3611
+ }
3612
+ ];
3613
+ if (document.declarations) {
3614
+ guidance.push({
3615
+ kind: "declarations",
3616
+ title: "Declarations establish policy facts",
3617
+ detail: "Declarations and schedules generally establish named insured, policy period, limits, deductibles, premium, and rating facts unless modified elsewhere."
3618
+ });
3619
+ }
3620
+ if (document.endorsements?.length || document.formInventory?.some((form) => form.formType === "endorsement")) {
3621
+ guidance.push({
3622
+ kind: "endorsement_override",
3623
+ title: "Endorsements may override base terms",
3624
+ detail: "Endorsements and change forms can add, remove, or override base policy wording. When terms conflict, inspect the effective endorsement language and source page."
3625
+ });
3626
+ }
3627
+ return guidance;
3628
+ }
3629
+ function attachDocumentStructure(params) {
3630
+ const docRecord = params.document;
3631
+ const sections = Array.isArray(params.document.sections) ? params.document.sections : [];
3632
+ const existingOutline = Array.isArray(docRecord.documentOutline) ? docRecord.documentOutline : [];
3633
+ const documentOutline = existingOutline.length > 0 ? existingOutline : sections.length > 0 ? sections.map((section, index) => buildNodeFromSection(section, index)) : buildNodesFromSourceSpans(params.sourceSpans);
3634
+ if (documentOutline.length > 0) {
3635
+ attachDocumentNodeIds(params.document, documentOutline);
3636
+ }
3637
+ const metadata = {
3638
+ ...docRecord.documentMetadata && typeof docRecord.documentMetadata === "object" ? docRecord.documentMetadata : {},
3639
+ ...params.document.formInventory?.length ? { formInventory: params.document.formInventory } : {},
3640
+ ...documentOutline.length > 0 ? { tableOfContents: flattenToc(documentOutline) } : {},
3641
+ ...params.pageAssignments.length > 0 ? { pageMap: buildPageMap(params.pageAssignments, params.sourceSpans, params.document) } : {},
3642
+ agentGuidance: buildAgentGuidance(params.document)
3643
+ };
3644
+ docRecord.documentMetadata = metadata;
3645
+ docRecord.documentOutline = documentOutline;
3646
+ return params.document;
3647
+ }
3648
+
3333
3649
  // src/prompts/coordinator/format.ts
3334
3650
  function buildFormatPrompt(entries) {
3335
3651
  const block = entries.map((e) => `===ENTRY ${e.id}===
@@ -3929,6 +4245,8 @@ function chunkDocument(doc) {
3929
4245
  {
3930
4246
  formNumber: form.formNumber,
3931
4247
  formType: form.formType,
4248
+ documentNodeId: form.documentNodeId,
4249
+ sourceSpanIds: form.sourceSpanIds?.join(","),
3932
4250
  documentType: doc.type
3933
4251
  }
3934
4252
  );
@@ -3955,6 +4273,7 @@ function chunkDocument(doc) {
3955
4273
  formNumber: end.formNumber,
3956
4274
  pageStart: end.pageStart,
3957
4275
  pageEnd: end.pageEnd,
4276
+ documentNodeId: end.documentNodeId,
3958
4277
  sourceSpanIds: end.sourceSpanIds?.join(","),
3959
4278
  sourceTextHash: end.sourceTextHash,
3960
4279
  documentType: doc.type
@@ -3966,6 +4285,8 @@ function chunkDocument(doc) {
3966
4285
  ${exc.content}`.trim(), {
3967
4286
  formNumber: exc.formNumber,
3968
4287
  pageNumber: exc.pageNumber,
4288
+ documentNodeId: exc.documentNodeId,
4289
+ sourceSpanIds: exc.sourceSpanIds?.join(","),
3969
4290
  documentType: doc.type
3970
4291
  });
3971
4292
  });
@@ -3983,6 +4304,8 @@ ${exc.content}`.trim(), {
3983
4304
  conditionName: cond.name,
3984
4305
  conditionType: cond.conditionType,
3985
4306
  pageNumber: cond.pageNumber,
4307
+ documentNodeId: cond.documentNodeId,
4308
+ sourceSpanIds: cond.sourceSpanIds?.join(","),
3986
4309
  documentType: doc.type
3987
4310
  }
3988
4311
  );
@@ -4004,6 +4327,9 @@ ${exc.content}`.trim(), {
4004
4327
  formTitle: firstString2(definition, ["formTitle"]),
4005
4328
  pageNumber: typeof definition.pageNumber === "number" ? definition.pageNumber : void 0,
4006
4329
  sectionRef: firstString2(definition, ["sectionRef", "sectionTitle"]),
4330
+ documentNodeId: firstString2(definition, ["documentNodeId"]),
4331
+ sourceSpanIds: Array.isArray(definition.sourceSpanIds) ? definition.sourceSpanIds.join(",") : void 0,
4332
+ sourceTextHash: firstString2(definition, ["sourceTextHash"]),
4007
4333
  documentType: doc.type
4008
4334
  }
4009
4335
  );
@@ -4032,6 +4358,9 @@ ${exc.content}`.trim(), {
4032
4358
  formTitle: firstString2(coveredReason, ["formTitle"]),
4033
4359
  pageNumber: typeof coveredReason.pageNumber === "number" ? coveredReason.pageNumber : void 0,
4034
4360
  sectionRef: firstString2(coveredReason, ["sectionRef", "sectionTitle"]),
4361
+ documentNodeId: firstString2(coveredReason, ["documentNodeId"]),
4362
+ sourceSpanIds: Array.isArray(coveredReason.sourceSpanIds) ? coveredReason.sourceSpanIds.join(",") : void 0,
4363
+ sourceTextHash: firstString2(coveredReason, ["sourceTextHash"]),
4035
4364
  documentType: doc.type
4036
4365
  }
4037
4366
  );
@@ -4093,6 +4422,7 @@ ${declLines.join("\n")}`, declMeta);
4093
4422
  evidenceKind: "navigation",
4094
4423
  sectionType: sec.type,
4095
4424
  sectionNumber: sec.sectionNumber,
4425
+ documentNodeId: sec.documentNodeId,
4096
4426
  pageStart: sec.pageStart,
4097
4427
  pageEnd: sec.pageEnd,
4098
4428
  sourceSpanIds: sec.sourceSpanIds?.join(","),
@@ -4116,6 +4446,7 @@ ${declLines.join("\n")}`, declMeta);
4116
4446
  sectionType: sec.type,
4117
4447
  parentSection: sec.title,
4118
4448
  sectionNumber: sub.sectionNumber,
4449
+ documentNodeId: sub.documentNodeId,
4119
4450
  pageNumber: sub.pageNumber,
4120
4451
  sourceSpanIds: sub.sourceSpanIds?.join(","),
4121
4452
  sourceTextHash: sub.sourceTextHash,
@@ -4124,6 +4455,31 @@ ${declLines.join("\n")}`, declMeta);
4124
4455
  );
4125
4456
  });
4126
4457
  });
4458
+ asRecordArray(extendedDoc.documentOutline).forEach((node, i) => {
4459
+ const title = firstString2(node, ["title", "originalTitle"]) ?? `Document Node ${i + 1}`;
4460
+ const children = asRecordArray(node.children);
4461
+ pushChunk(
4462
+ `section:outline:${i}`,
4463
+ "section",
4464
+ lines([
4465
+ `Document Outline: ${title}`,
4466
+ firstString2(node, ["label", "type"]) ? `Label: ${firstString2(node, ["label", "type"])}` : null,
4467
+ typeof node.pageStart === "number" ? `Pages: ${node.pageStart}${typeof node.pageEnd === "number" ? `-${node.pageEnd}` : ""}` : null,
4468
+ firstString2(node, ["excerpt", "content"]),
4469
+ children.length > 0 ? `Children: ${children.map((child, childIndex) => firstString2(child, ["title", "originalTitle"]) ?? `Child ${childIndex + 1}`).join(", ")}` : null
4470
+ ]),
4471
+ {
4472
+ evidenceKind: "navigation",
4473
+ documentNodeId: firstString2(node, ["id"]),
4474
+ sectionType: firstString2(node, ["type", "label"]),
4475
+ pageStart: typeof node.pageStart === "number" ? node.pageStart : void 0,
4476
+ pageEnd: typeof node.pageEnd === "number" ? node.pageEnd : void 0,
4477
+ sourceSpanIds: Array.isArray(node.sourceSpanIds) ? node.sourceSpanIds.join(",") : void 0,
4478
+ sourceTextHash: firstString2(node, ["sourceTextHash"]),
4479
+ documentType: doc.type
4480
+ }
4481
+ );
4482
+ });
4127
4483
  doc.locations?.forEach((loc, i) => {
4128
4484
  chunks.push({
4129
4485
  id: `${docId}:location:${i}`,
@@ -6947,13 +7303,13 @@ async function resolveReferentialCoverages(params) {
6947
7303
  function textValue(value) {
6948
7304
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
6949
7305
  }
6950
- function numberValue(value) {
7306
+ function numberValue2(value) {
6951
7307
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
6952
7308
  }
6953
7309
  function normalize(value) {
6954
7310
  return value.toLowerCase().replace(/&/g, "and").replace(/[^a-z0-9]+/g, " ").trim();
6955
7311
  }
6956
- function sourceUnit3(span) {
7312
+ function sourceUnit4(span) {
6957
7313
  return span.sourceUnit ?? span.metadata?.sourceUnit;
6958
7314
  }
6959
7315
  function pageNumber(span) {
@@ -7023,7 +7379,7 @@ function firstField(fields, patterns) {
7023
7379
  }
7024
7380
  function coverageFromRow(span) {
7025
7381
  const rowText = span.text.trim();
7026
- if (!rowText || sourceUnit3(span) !== "table_row") return void 0;
7382
+ if (!rowText || sourceUnit4(span) !== "table_row") return void 0;
7027
7383
  if (span.table?.isHeader || span.metadata?.isHeader === "true") return void 0;
7028
7384
  const fields = splitRowFields(rowText);
7029
7385
  let name;
@@ -7085,7 +7441,7 @@ function coverageKey(coverage) {
7085
7441
  textValue(coverage.name) ?? "",
7086
7442
  textValue(coverage.limit) ?? "",
7087
7443
  textValue(coverage.limitType) ?? "",
7088
- numberValue(coverage.pageNumber) ?? ""
7444
+ numberValue2(coverage.pageNumber) ?? ""
7089
7445
  ].map((part) => normalize(String(part))).join("|");
7090
7446
  }
7091
7447
  function rowMatchesExisting(row, existing) {
@@ -7103,7 +7459,7 @@ function recoverCoverageScheduleRows(params) {
7103
7459
  const payload = params.memory.get("coverage_limits");
7104
7460
  const existing = Array.isArray(payload?.coverages) ? payload.coverages : [];
7105
7461
  const pages = coveragePages(params.pageAssignments);
7106
- const candidates = params.sourceSpans.filter((span) => sourceUnit3(span) === "table_row").filter((span) => {
7462
+ const candidates = params.sourceSpans.filter((span) => sourceUnit4(span) === "table_row").filter((span) => {
7107
7463
  const page = pageNumber(span);
7108
7464
  return page !== void 0 && pages.has(page);
7109
7465
  }).map(coverageFromRow).filter((coverage) => Boolean(coverage));
@@ -7778,7 +8134,10 @@ var ARRAY_PATHS = [
7778
8134
  { memoryKey: "sections", arrayKeys: ["sections"] },
7779
8135
  { memoryKey: "definitions", arrayKeys: ["definitions"] },
7780
8136
  { memoryKey: "covered_reasons", arrayKeys: ["coveredReasons", "covered_reasons"] },
7781
- { memoryKey: "declarations", arrayKeys: ["fields"] }
8137
+ { memoryKey: "declarations", arrayKeys: ["fields"] },
8138
+ { memoryKey: "premium_breakdown", arrayKeys: ["premiumBreakdown", "taxesAndFees"] },
8139
+ { memoryKey: "supplementary", arrayKeys: ["auxiliaryFacts", "supplementaryFacts"] },
8140
+ { memoryKey: "form_inventory", arrayKeys: ["forms"] }
7782
8141
  ];
7783
8142
  function normalize2(value) {
7784
8143
  return value.replace(/\s+/g, " ").trim().toLowerCase();
@@ -7790,7 +8149,7 @@ function textValue2(record, ...keys) {
7790
8149
  }
7791
8150
  return void 0;
7792
8151
  }
7793
- function numberValue2(record, ...keys) {
8152
+ function numberValue3(record, ...keys) {
7794
8153
  for (const key of keys) {
7795
8154
  const value = record[key];
7796
8155
  if (typeof value === "number" && Number.isFinite(value)) return value;
@@ -7823,11 +8182,11 @@ function textMatches(record, span) {
7823
8182
  function sourceHashFor(spans) {
7824
8183
  return spans.map((span) => span.textHash ?? span.hash).filter(Boolean).join(":") || void 0;
7825
8184
  }
7826
- function sourceUnit4(span) {
8185
+ function sourceUnit5(span) {
7827
8186
  return span.sourceUnit ?? span.metadata?.sourceUnit;
7828
8187
  }
7829
8188
  function hierarchyScore(span) {
7830
- switch (sourceUnit4(span)) {
8189
+ switch (sourceUnit5(span)) {
7831
8190
  case "table_row":
7832
8191
  return 5;
7833
8192
  case "table":
@@ -7850,8 +8209,8 @@ function preferParentRows(matches, sourceSpans) {
7850
8209
  const expanded = [];
7851
8210
  const seen = /* @__PURE__ */ new Set();
7852
8211
  for (const match of matches) {
7853
- const parent = sourceUnit4(match) === "table_cell" ? byId.get(parentRowId(match) ?? "") : void 0;
7854
- const preferred = parent && sourceUnit4(parent) === "table_row" ? parent : match;
8212
+ const parent = sourceUnit5(match) === "table_cell" ? byId.get(parentRowId(match) ?? "") : void 0;
8213
+ const preferred = parent && sourceUnit5(parent) === "table_row" ? parent : match;
7855
8214
  if (seen.has(preferred.id)) continue;
7856
8215
  seen.add(preferred.id);
7857
8216
  expanded.push(preferred);
@@ -7860,8 +8219,8 @@ function preferParentRows(matches, sourceSpans) {
7860
8219
  }
7861
8220
  function findSourceSpansForRecord(record, sourceSpans) {
7862
8221
  if (sourceSpans.length === 0) return [];
7863
- const pageStart = numberValue2(record, "pageNumber", "pageStart");
7864
- const pageEnd = numberValue2(record, "pageNumber", "pageEnd");
8222
+ const pageStart = numberValue3(record, "pageNumber", "pageStart");
8223
+ const pageEnd = numberValue3(record, "pageNumber", "pageEnd");
7865
8224
  const scored = sourceSpans.map((span) => {
7866
8225
  let score = 0;
7867
8226
  if (pageOverlaps(pageStart, pageEnd, span)) score += 4;
@@ -8804,6 +9163,7 @@ ${pageText}`;
8804
9163
  }));
8805
9164
  onProgress?.("Assembling document...");
8806
9165
  const document = assembleDocument(id, documentType, memory);
9166
+ attachDocumentStructure({ document, pageAssignments, sourceSpans });
8807
9167
  await pipelineCtx.save("assemble", {
8808
9168
  id,
8809
9169
  pageCount,
@@ -12601,6 +12961,11 @@ export {
12601
12961
  DeductibleTypeSchema,
12602
12962
  DefenseCostTreatmentSchema,
12603
12963
  DefinitionSchema,
12964
+ DocumentAgentGuidanceSchema,
12965
+ DocumentMetadataSchema,
12966
+ DocumentNodeSchema,
12967
+ DocumentPageMapEntrySchema,
12968
+ DocumentTableOfContentsEntrySchema,
12604
12969
  DocumentTypeSchema,
12605
12970
  DriverRecordSchema,
12606
12971
  DwellingDetailsSchema,