@claritylabs/cl-sdk 3.1.17 → 3.1.18

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
@@ -9210,11 +9210,20 @@ function coverageTextForSelection(coverage) {
9210
9210
  ])
9211
9211
  ].filter(Boolean).join(" ");
9212
9212
  }
9213
+ function coverageCleanupEntries(profile, coverageIndexes) {
9214
+ if (!coverageIndexes) {
9215
+ return profile.coverages.map((coverage, coverageIndex) => ({ coverage, coverageIndex }));
9216
+ }
9217
+ return [...new Set(coverageIndexes)].sort((left, right) => left - right).map((coverageIndex) => {
9218
+ const coverage = profile.coverages[coverageIndex];
9219
+ return coverage ? { coverage, coverageIndex } : void 0;
9220
+ }).filter((entry) => Boolean(entry));
9221
+ }
9213
9222
  function nodeTextMatchesCoverage(node, coverageTerms) {
9214
9223
  const text = nodeTextForSelection(node).toLowerCase();
9215
9224
  return coverageTerms.some((term) => term.length >= 5 && text.includes(term));
9216
9225
  }
9217
- function selectCoverageCleanupNodes(sourceTree, profile) {
9226
+ function selectCoverageCleanupNodes(sourceTree, coverages) {
9218
9227
  const nodeById = new Map(sourceTree.map((node) => [node.id, node]));
9219
9228
  const childrenByParent = /* @__PURE__ */ new Map();
9220
9229
  for (const node of sourceTree) {
@@ -9232,12 +9241,12 @@ function selectCoverageCleanupNodes(sourceTree, profile) {
9232
9241
  const current = selected.get(node.id);
9233
9242
  if (!current || score > current.score) selected.set(node.id, { node, score });
9234
9243
  };
9235
- const sourceNodeIds = uniqueStrings(profile.coverages.flatMap((coverage) => [
9244
+ const sourceNodeIds = uniqueStrings(coverages.flatMap((coverage) => [
9236
9245
  ...coverage.sourceNodeIds,
9237
9246
  ...coverage.limits.flatMap((term) => term.sourceNodeIds)
9238
9247
  ]));
9239
9248
  const coveragePages2 = /* @__PURE__ */ new Set();
9240
- const coverageTerms = uniqueStrings(profile.coverages.flatMap(
9249
+ const coverageTerms = uniqueStrings(coverages.flatMap(
9241
9250
  (coverage) => coverageTextForSelection(coverage).toLowerCase().split(/[^a-z0-9$,.]+/i).filter((part) => part.length >= 5)
9242
9251
  ));
9243
9252
  for (const id of sourceNodeIds) {
@@ -9280,8 +9289,9 @@ function selectCoverageCleanupNodes(sourceTree, profile) {
9280
9289
  (left, right) => (left.node.pageStart ?? Number.MAX_SAFE_INTEGER) - (right.node.pageStart ?? Number.MAX_SAFE_INTEGER) || left.node.order - right.node.order
9281
9290
  ).map((entry) => entry.node);
9282
9291
  }
9283
- function buildOperationalProfileCleanupPrompt(sourceTree, profile) {
9284
- const nodes = selectCoverageCleanupNodes(sourceTree, profile).map((node) => compactNode(
9292
+ function buildOperationalProfileCleanupPrompt(sourceTree, profile, options = {}) {
9293
+ const coverageEntries = coverageCleanupEntries(profile, options.coverageIndexes);
9294
+ const nodes = selectCoverageCleanupNodes(sourceTree, coverageEntries.map((entry) => entry.coverage)).map((node) => compactNode(
9285
9295
  node,
9286
9296
  node.kind === "page" || node.kind === "page_group" ? 260 : node.kind === "table_row" || node.kind === "table_cell" ? 520 : 360
9287
9297
  ));
@@ -9289,9 +9299,12 @@ function buildOperationalProfileCleanupPrompt(sourceTree, profile) {
9289
9299
  documentType: profile.documentType,
9290
9300
  policyTypes: profile.policyTypes,
9291
9301
  coverageTypes: profile.coverageTypes,
9292
- coverages: profile.coverages.map(compactCoverageForCleanup)
9302
+ coverages: coverageEntries.map(({ coverage, coverageIndex }) => compactCoverageForCleanup(coverage, coverageIndex))
9293
9303
  };
9294
9304
  return `Review and clean a source-backed operational profile projection for an insurance policy.
9305
+ ${options.label ? `
9306
+ Coverage group: ${options.label}
9307
+ ` : ""}
9295
9308
 
9296
9309
  Task:
9297
9310
  - Inspect the candidate coverage projection against the source nodes.
@@ -11376,7 +11389,8 @@ async function runVisualTableRepair(params) {
11376
11389
  if (candidates.length === 0) return { sourceTree: params.sourceTree, warnings: [] };
11377
11390
  let sourceTree = params.sourceTree;
11378
11391
  const warnings = [];
11379
- for (const [index, candidate] of candidates.entries()) {
11392
+ const repairResults = await Promise.all(candidates.map(async (candidate, index) => {
11393
+ const label = `source_tree_visual_table_repair_p${candidate.page}`;
11380
11394
  try {
11381
11395
  const budget = params.resolveBudget("extraction_source_tree", 1800);
11382
11396
  const maxTokens = Math.min(budget.maxTokens, 2400);
@@ -11390,7 +11404,7 @@ async function runVisualTableRepair(params) {
11390
11404
  taskKind: "extraction_source_tree",
11391
11405
  budgetDiagnostics: { ...budget, maxTokens },
11392
11406
  trace: {
11393
- label: `source_tree_visual_table_repair_p${candidate.page}`,
11407
+ label,
11394
11408
  startPage: candidate.page,
11395
11409
  endPage: candidate.page,
11396
11410
  batchIndex: index + 1,
@@ -11403,20 +11417,38 @@ async function runVisualTableRepair(params) {
11403
11417
  log: params.log
11404
11418
  }
11405
11419
  );
11406
- params.trackUsage(response.usage, {
11407
- taskKind: "extraction_source_tree",
11408
- label: `source_tree_visual_table_repair_p${candidate.page}`,
11420
+ return {
11421
+ index,
11422
+ candidate,
11423
+ label,
11409
11424
  maxTokens,
11410
- durationMs: Date.now() - startedAt
11411
- });
11412
- const repair = response.object;
11413
- sourceTree = applyVisualTableRepair(sourceTree, repair);
11414
- warnings.push(...repair.warnings.map(
11415
- (warning) => `Visual table repair warning on page ${candidate.page}: ${warning}`
11416
- ));
11425
+ durationMs: Date.now() - startedAt,
11426
+ usage: response.usage,
11427
+ repair: response.object
11428
+ };
11417
11429
  } catch (error) {
11418
- warnings.push(`Visual table repair skipped on page ${candidate.page}; parsed table kept (${error instanceof Error ? error.message : String(error)})`);
11430
+ return {
11431
+ index,
11432
+ candidate,
11433
+ error: error instanceof Error ? error.message : String(error)
11434
+ };
11435
+ }
11436
+ }));
11437
+ for (const result of repairResults.sort((left, right) => left.index - right.index)) {
11438
+ if ("error" in result) {
11439
+ warnings.push(`Visual table repair skipped on page ${result.candidate.page}; parsed table kept (${result.error})`);
11440
+ continue;
11419
11441
  }
11442
+ params.trackUsage(result.usage, {
11443
+ taskKind: "extraction_source_tree",
11444
+ label: result.label,
11445
+ maxTokens: result.maxTokens,
11446
+ durationMs: result.durationMs
11447
+ });
11448
+ sourceTree = applyVisualTableRepair(sourceTree, result.repair);
11449
+ warnings.push(...result.repair.warnings.map(
11450
+ (warning) => `Visual table repair warning on page ${result.candidate.page}: ${warning}`
11451
+ ));
11420
11452
  }
11421
11453
  return { sourceTree, warnings };
11422
11454
  }
@@ -11513,6 +11545,32 @@ var NORMALIZED_COMPATIBILITY_FIELDS = /* @__PURE__ */ new Set([
11513
11545
  "insurer",
11514
11546
  "broker"
11515
11547
  ]);
11548
+ function coverageBelongsToEndorsementCleanupChunk(coverage) {
11549
+ return coverage.coverageOrigin === "endorsement" || Boolean(coverage.endorsementNumber);
11550
+ }
11551
+ function coverageCleanupChunks(profile) {
11552
+ const basePolicy = [];
11553
+ const endorsements = [];
11554
+ profile.coverages.forEach((coverage, coverageIndex) => {
11555
+ if (coverageBelongsToEndorsementCleanupChunk(coverage)) {
11556
+ endorsements.push(coverageIndex);
11557
+ } else {
11558
+ basePolicy.push(coverageIndex);
11559
+ }
11560
+ });
11561
+ return [
11562
+ basePolicy.length ? {
11563
+ group: "base_policy",
11564
+ label: "Coverage cleanup: base policy",
11565
+ coverageIndexes: basePolicy
11566
+ } : void 0,
11567
+ endorsements.length ? {
11568
+ group: "endorsements",
11569
+ label: "Coverage cleanup: endorsements",
11570
+ coverageIndexes: endorsements
11571
+ } : void 0
11572
+ ].filter((chunk) => Boolean(chunk));
11573
+ }
11516
11574
  function valueOf(profile, key) {
11517
11575
  const value = profile[key];
11518
11576
  if (!value || typeof value !== "object" || Array.isArray(value) || !("value" in value)) return void 0;
@@ -11669,9 +11727,9 @@ async function runSourceTreeExtraction(params) {
11669
11727
  };
11670
11728
  if (shouldRunSourceTreeOrganizer(sourceTree, sourceSpans)) {
11671
11729
  try {
11672
- const organizations = [];
11673
11730
  const batches = organizationBatches(sourceTree);
11674
- for (const [batchIndex, batch] of batches.entries()) {
11731
+ const organizationResults = await Promise.all(batches.map(async (batch, batchIndex) => {
11732
+ const label = batches.length > 1 ? `source_tree_organizer_${batchIndex + 1}` : "source_tree_organizer";
11675
11733
  const budget = params.resolveBudget("extraction_source_tree", 4096);
11676
11734
  const startedAt = Date.now();
11677
11735
  const response = await safeGenerateObject(
@@ -11681,20 +11739,37 @@ async function runSourceTreeExtraction(params) {
11681
11739
  schema: SourceTreeOrganizationSchema,
11682
11740
  maxTokens: budget.maxTokens,
11683
11741
  taskKind: "extraction_source_tree",
11684
- budgetDiagnostics: budget
11742
+ budgetDiagnostics: budget,
11743
+ trace: {
11744
+ label,
11745
+ batchIndex: batchIndex + 1,
11746
+ batchCount: batches.length,
11747
+ sourceBacked: true
11748
+ }
11685
11749
  },
11686
11750
  {
11687
11751
  fallback: { labels: [], groups: [] },
11688
11752
  log: params.log
11689
11753
  }
11690
11754
  );
11691
- localTrack(response.usage, {
11755
+ return {
11756
+ batchIndex,
11757
+ label,
11758
+ budget,
11759
+ durationMs: Date.now() - startedAt,
11760
+ usage: response.usage,
11761
+ organization: response.object
11762
+ };
11763
+ }));
11764
+ const organizations = [];
11765
+ for (const result of organizationResults.sort((left, right) => left.batchIndex - right.batchIndex)) {
11766
+ localTrack(result.usage, {
11692
11767
  taskKind: "extraction_source_tree",
11693
- label: batches.length > 1 ? `source_tree_organizer_${batchIndex + 1}` : "source_tree_organizer",
11694
- maxTokens: budget.maxTokens,
11695
- durationMs: Date.now() - startedAt
11768
+ label: result.label,
11769
+ maxTokens: result.budget.maxTokens,
11770
+ durationMs: result.durationMs
11696
11771
  });
11697
- organizations.push(response.object);
11772
+ organizations.push(result.organization);
11698
11773
  }
11699
11774
  sourceTree = applyOrganization(sourceTree, mergeOrganizationResults(organizations));
11700
11775
  } catch (error) {
@@ -11783,33 +11858,64 @@ async function runSourceTreeExtraction(params) {
11783
11858
  try {
11784
11859
  const validNodeIds = new Set(sourceTree.map((node) => node.id));
11785
11860
  const validSpanIds = new Set(sourceSpans.map((span) => span.id));
11786
- const budget = params.resolveBudget("extraction_coverage_cleanup", 4096);
11787
- const startedAt = Date.now();
11788
- const response = await safeGenerateObject(
11789
- params.generateObject,
11790
- {
11791
- prompt: buildOperationalProfileCleanupPrompt(sourceTree, operationalProfile),
11792
- schema: OperationalProfileCleanupSchema,
11793
- maxTokens: budget.maxTokens,
11861
+ const chunks = coverageCleanupChunks(operationalProfile);
11862
+ if (chunks.length > 1) {
11863
+ await params.log?.(`Operational profile coverage cleanup reviewing ${chunks.length} coverage groups in parallel`);
11864
+ }
11865
+ const cleanupResults = await Promise.all(chunks.map(async (chunk, batchIndex) => {
11866
+ const budget = params.resolveBudget("extraction_coverage_cleanup", 4096);
11867
+ const startedAt = Date.now();
11868
+ const response = await safeGenerateObject(
11869
+ params.generateObject,
11870
+ {
11871
+ prompt: buildOperationalProfileCleanupPrompt(sourceTree, operationalProfile, {
11872
+ coverageIndexes: chunk.coverageIndexes,
11873
+ label: chunk.label
11874
+ }),
11875
+ schema: OperationalProfileCleanupSchema,
11876
+ maxTokens: budget.maxTokens,
11877
+ taskKind: "extraction_coverage_cleanup",
11878
+ budgetDiagnostics: budget,
11879
+ providerOptions: params.providerOptions,
11880
+ trace: {
11881
+ phase: "coverage_cleanup",
11882
+ label: chunk.label,
11883
+ batchIndex: batchIndex + 1,
11884
+ batchCount: chunks.length,
11885
+ coverageGroup: chunk.group,
11886
+ itemCount: chunk.coverageIndexes.length,
11887
+ sourceBacked: true
11888
+ }
11889
+ },
11890
+ {
11891
+ fallback: { coverageDecisions: [], warnings: [] },
11892
+ maxRetries: 0,
11893
+ log: params.log
11894
+ }
11895
+ );
11896
+ return {
11897
+ batchIndex,
11898
+ chunk,
11899
+ budget,
11900
+ durationMs: Date.now() - startedAt,
11901
+ usage: response.usage,
11902
+ cleanup: response.object
11903
+ };
11904
+ }));
11905
+ const cleanup = { coverageDecisions: [], warnings: [] };
11906
+ for (const result of cleanupResults.sort((left, right) => left.batchIndex - right.batchIndex)) {
11907
+ localTrack(result.usage, {
11794
11908
  taskKind: "extraction_coverage_cleanup",
11795
- budgetDiagnostics: budget,
11796
- providerOptions: params.providerOptions,
11797
- trace: { phase: "coverage_cleanup", sourceBacked: true }
11798
- },
11799
- {
11800
- fallback: { coverageDecisions: [], warnings: [] },
11801
- log: params.log
11802
- }
11803
- );
11804
- localTrack(response.usage, {
11805
- taskKind: "extraction_coverage_cleanup",
11806
- label: "operational_profile_cleanup",
11807
- maxTokens: budget.maxTokens,
11808
- durationMs: Date.now() - startedAt
11809
- });
11909
+ label: result.chunk.label,
11910
+ maxTokens: result.budget.maxTokens,
11911
+ durationMs: result.durationMs
11912
+ });
11913
+ cleanup.coverageDecisions.push(...result.cleanup.coverageDecisions);
11914
+ cleanup.warnings.push(...result.cleanup.warnings);
11915
+ }
11810
11916
  operationalProfile = applyOperationalProfileCleanup(
11811
11917
  operationalProfile,
11812
- response.object,
11918
+ cleanup,
11813
11919
  validNodeIds,
11814
11920
  validSpanIds
11815
11921
  );
@@ -11863,6 +11969,7 @@ function createExtractor(config) {
11863
11969
  sourceStore,
11864
11970
  qualityGate = "warn",
11865
11971
  modelCapabilities,
11972
+ modelCapabilitiesByTaskKind,
11866
11973
  modelBudgetConstraints,
11867
11974
  onCheckpointSave
11868
11975
  } = config;
@@ -11879,10 +11986,11 @@ function createExtractor(config) {
11879
11986
  };
11880
11987
  let activeProviderOptions = providerOptions;
11881
11988
  function resolveBudget(taskKind, hintTokens) {
11989
+ const taskModelCapabilities = modelCapabilitiesByTaskKind?.[taskKind] ?? modelCapabilities;
11882
11990
  return resolveModelBudget({
11883
11991
  taskKind,
11884
11992
  hintTokens,
11885
- modelCapabilities,
11993
+ modelCapabilities: taskModelCapabilities,
11886
11994
  constraint: modelBudgetConstraints?.[taskKind]
11887
11995
  });
11888
11996
  }