@claritylabs/cl-sdk 3.0.1 → 3.0.3

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
@@ -9236,6 +9236,8 @@ var ORGANIZABLE_KINDS = [
9236
9236
  "schedule",
9237
9237
  "clause"
9238
9238
  ];
9239
+ var ORGANIZATION_TOP_LEVEL_BATCH_SIZE = 80;
9240
+ var ORGANIZATION_CHILD_CONTEXT_LIMIT = 4;
9239
9241
  var SourceTreeOrganizationSchema = import_zod41.z.object({
9240
9242
  labels: import_zod41.z.array(import_zod41.z.object({
9241
9243
  nodeId: import_zod41.z.string(),
@@ -9255,20 +9257,20 @@ var SourceTreeOrganizationSchema = import_zod41.z.object({
9255
9257
  ]).optional(),
9256
9258
  title: import_zod41.z.string().optional(),
9257
9259
  description: import_zod41.z.string().optional()
9258
- })).default([]),
9260
+ })),
9259
9261
  groups: import_zod41.z.array(import_zod41.z.object({
9260
9262
  kind: import_zod41.z.enum(ORGANIZABLE_KINDS),
9261
9263
  title: import_zod41.z.string(),
9262
9264
  description: import_zod41.z.string().optional(),
9263
9265
  childNodeIds: import_zod41.z.array(import_zod41.z.string()).min(1)
9264
- })).default([])
9266
+ }))
9265
9267
  });
9266
9268
  var SourceBackedValueForPromptSchema = import_zod41.z.object({
9267
9269
  value: import_zod41.z.string(),
9268
9270
  normalizedValue: import_zod41.z.string().optional(),
9269
9271
  confidence: import_zod41.z.enum(["low", "medium", "high"]).optional(),
9270
- sourceNodeIds: import_zod41.z.array(import_zod41.z.string()).default([]),
9271
- sourceSpanIds: import_zod41.z.array(import_zod41.z.string()).default([])
9272
+ sourceNodeIds: import_zod41.z.array(import_zod41.z.string()),
9273
+ sourceSpanIds: import_zod41.z.array(import_zod41.z.string())
9272
9274
  });
9273
9275
  var OperationalProfilePromptSchema = import_zod41.z.object({
9274
9276
  documentType: import_zod41.z.enum(["policy", "quote"]).optional(),
@@ -9290,8 +9292,8 @@ var OperationalProfilePromptSchema = import_zod41.z.object({
9290
9292
  premium: import_zod41.z.string().optional(),
9291
9293
  formNumber: import_zod41.z.string().optional(),
9292
9294
  sectionRef: import_zod41.z.string().optional(),
9293
- sourceNodeIds: import_zod41.z.array(import_zod41.z.string()).default([]),
9294
- sourceSpanIds: import_zod41.z.array(import_zod41.z.string()).default([])
9295
+ sourceNodeIds: import_zod41.z.array(import_zod41.z.string()),
9296
+ sourceSpanIds: import_zod41.z.array(import_zod41.z.string())
9295
9297
  })).optional(),
9296
9298
  sourceNodeIds: import_zod41.z.array(import_zod41.z.string()).optional(),
9297
9299
  sourceSpanIds: import_zod41.z.array(import_zod41.z.string()).optional()
@@ -9300,7 +9302,7 @@ function cleanText(value, fallback) {
9300
9302
  const text = value?.replace(/\s+/g, " ").trim();
9301
9303
  return text || fallback;
9302
9304
  }
9303
- function compactNode(node) {
9305
+ function compactNode(node, maxText = 700) {
9304
9306
  return {
9305
9307
  id: node.id,
9306
9308
  kind: node.kind,
@@ -9309,19 +9311,89 @@ function compactNode(node) {
9309
9311
  pageStart: node.pageStart,
9310
9312
  pageEnd: node.pageEnd,
9311
9313
  sourceSpanIds: node.sourceSpanIds.slice(0, 8),
9312
- text: (node.textExcerpt ?? node.description).slice(0, 700)
9314
+ text: (node.textExcerpt ?? node.description).slice(0, maxText)
9315
+ };
9316
+ }
9317
+ function nodesByParent(sourceTree) {
9318
+ const byParent = /* @__PURE__ */ new Map();
9319
+ for (const node of sourceTree) {
9320
+ const children = byParent.get(node.parentId) ?? [];
9321
+ children.push(node);
9322
+ byParent.set(node.parentId, children);
9323
+ }
9324
+ for (const children of byParent.values()) {
9325
+ children.sort((left, right) => left.order - right.order || left.id.localeCompare(right.id));
9326
+ }
9327
+ return byParent;
9328
+ }
9329
+ function sourceTreeRootId(sourceTree) {
9330
+ return sourceTree.find((node) => node.kind === "document")?.id;
9331
+ }
9332
+ function organizationBatches(sourceTree) {
9333
+ const byParent = nodesByParent(sourceTree);
9334
+ const rootId = sourceTreeRootId(sourceTree);
9335
+ const topLevelNodes = (byParent.get(rootId) ?? []).filter((node) => node.kind !== "document");
9336
+ if (topLevelNodes.length === 0) {
9337
+ const nodes = sourceTree.filter((node) => node.kind !== "document").slice(0, 240);
9338
+ return [{
9339
+ label: "fallback node prefix because no document root children were found",
9340
+ topLevelNodeIds: nodes.map((node) => node.id),
9341
+ nodes
9342
+ }];
9343
+ }
9344
+ const batches = [];
9345
+ for (let index = 0; index < topLevelNodes.length; index += ORGANIZATION_TOP_LEVEL_BATCH_SIZE) {
9346
+ const topLevelBatch = topLevelNodes.slice(index, index + ORGANIZATION_TOP_LEVEL_BATCH_SIZE);
9347
+ const candidates = /* @__PURE__ */ new Map();
9348
+ for (const node of topLevelBatch) {
9349
+ candidates.set(node.id, node);
9350
+ const childContext = (byParent.get(node.id) ?? []).filter((child) => child.kind !== "text" && child.kind !== "table_cell").slice(0, ORGANIZATION_CHILD_CONTEXT_LIMIT);
9351
+ for (const child of childContext) {
9352
+ candidates.set(child.id, child);
9353
+ }
9354
+ }
9355
+ batches.push({
9356
+ label: `top-level nodes ${index + 1}-${index + topLevelBatch.length} of ${topLevelNodes.length}`,
9357
+ topLevelNodeIds: topLevelBatch.map((node) => node.id),
9358
+ nodes: [...candidates.values()]
9359
+ });
9360
+ }
9361
+ return batches;
9362
+ }
9363
+ function mergeOrganizationResults(results) {
9364
+ const labels = /* @__PURE__ */ new Map();
9365
+ const groups = /* @__PURE__ */ new Map();
9366
+ for (const result of results) {
9367
+ for (const label of result.labels) {
9368
+ labels.set(label.nodeId, { ...labels.get(label.nodeId), ...label });
9369
+ }
9370
+ for (const group of result.groups) {
9371
+ const key = `${group.kind}:${group.childNodeIds.join("|")}`;
9372
+ groups.set(key, group);
9373
+ }
9374
+ }
9375
+ return {
9376
+ labels: [...labels.values()],
9377
+ groups: [...groups.values()]
9313
9378
  };
9314
9379
  }
9315
- function buildOrganizationPrompt(sourceTree) {
9316
- const nodes = sourceTree.filter((node) => node.kind !== "table_cell").slice(0, 180).map(compactNode);
9380
+ function buildOrganizationPrompt(batch) {
9381
+ const nodes = batch.nodes.map((node) => compactNode(node, node.kind === "page" ? 900 : 320));
9317
9382
  return `You organize an insurance document source tree.
9318
9383
 
9384
+ Scope:
9385
+ - ${batch.label}
9386
+ - The provided list is a bounded extraction-time batch. It is not necessarily the whole document.
9387
+ - Top-level page/form candidates in this batch: ${JSON.stringify(batch.topLevelNodeIds)}
9388
+
9319
9389
  Rules:
9320
9390
  - Use only node IDs from the provided list.
9321
9391
  - Do not invent text, page numbers, source spans, limits, or policy facts.
9322
- - You may relabel existing nodes and group adjacent top-level/page nodes when they are clearly one form, endorsement, declarations set, schedule, or clause family.
9392
+ - You may relabel existing nodes and group adjacent top-level/page nodes from this batch when they are clearly one form, endorsement, declarations set, schedule, or clause family.
9393
+ - Add concise, human-readable titles to generic text, table, row, and cell nodes when the text makes their role clear.
9323
9394
  - Groups must list existing childNodeIds only.
9324
9395
  - Keep descriptions short and useful for search.
9396
+ - Prefer the document's own form titles, endorsement titles, schedules, declarations headings, and page order over keyword-only guessing.
9325
9397
 
9326
9398
  Source nodes:
9327
9399
  ${JSON.stringify(nodes, null, 2)}
@@ -9361,8 +9433,9 @@ function groupNodeId(documentId, group) {
9361
9433
  }
9362
9434
  function applyOrganization(sourceTree, organization) {
9363
9435
  const byId = new Map(sourceTree.map((node) => [node.id, node]));
9436
+ const labels = new Map(organization.labels.map((label) => [label.nodeId, label]));
9364
9437
  let nextTree = sourceTree.map((node) => {
9365
- const label = organization.labels.find((item) => item.nodeId === node.id);
9438
+ const label = labels.get(node.id);
9366
9439
  if (!label) return node;
9367
9440
  return {
9368
9441
  ...node,
@@ -9371,7 +9444,7 @@ function applyOrganization(sourceTree, organization) {
9371
9444
  description: cleanText(label.description, node.description)
9372
9445
  };
9373
9446
  });
9374
- for (const group of organization.groups.slice(0, 40)) {
9447
+ for (const group of organization.groups) {
9375
9448
  const children = group.childNodeIds.map((id2) => byId.get(id2)).filter((node2) => Boolean(node2));
9376
9449
  if (children.length === 0) continue;
9377
9450
  const parentId = children[0].parentId;
@@ -9429,6 +9502,7 @@ function sourceTreeToOutline(sourceTree) {
9429
9502
  sourceSpanIds: node.sourceSpanIds,
9430
9503
  sourceTextHash: node.sourceSpanIds.join(":") || void 0,
9431
9504
  interpretationLabels: [node.kind],
9505
+ metadata: node.metadata,
9432
9506
  children: (byParent.get(node.id) ?? []).map(visit)
9433
9507
  });
9434
9508
  return (byParent.get(root?.id) ?? []).map(visit);
@@ -9552,30 +9626,35 @@ async function runSourceTreeExtraction(params) {
9552
9626
  params.trackUsage(usage, report);
9553
9627
  };
9554
9628
  try {
9555
- const budget = params.resolveBudget("extraction_source_tree", 4096);
9556
- const startedAt = Date.now();
9557
- const response = await safeGenerateObject(
9558
- params.generateObject,
9559
- {
9560
- prompt: buildOrganizationPrompt(sourceTree),
9561
- schema: SourceTreeOrganizationSchema,
9562
- maxTokens: budget.maxTokens,
9629
+ const organizations = [];
9630
+ const batches = organizationBatches(sourceTree);
9631
+ for (const [batchIndex, batch] of batches.entries()) {
9632
+ const budget = params.resolveBudget("extraction_source_tree", 4096);
9633
+ const startedAt = Date.now();
9634
+ const response = await safeGenerateObject(
9635
+ params.generateObject,
9636
+ {
9637
+ prompt: buildOrganizationPrompt(batch),
9638
+ schema: SourceTreeOrganizationSchema,
9639
+ maxTokens: budget.maxTokens,
9640
+ taskKind: "extraction_source_tree",
9641
+ budgetDiagnostics: budget,
9642
+ providerOptions: { ...params.providerOptions, sourceSpans: params.sourceSpans }
9643
+ },
9644
+ {
9645
+ fallback: { labels: [], groups: [] },
9646
+ log: params.log
9647
+ }
9648
+ );
9649
+ localTrack(response.usage, {
9563
9650
  taskKind: "extraction_source_tree",
9564
- budgetDiagnostics: budget,
9565
- providerOptions: { ...params.providerOptions, sourceSpans: params.sourceSpans }
9566
- },
9567
- {
9568
- fallback: { labels: [], groups: [] },
9569
- log: params.log
9570
- }
9571
- );
9572
- localTrack(response.usage, {
9573
- taskKind: "extraction_source_tree",
9574
- label: "source_tree_organizer",
9575
- maxTokens: budget.maxTokens,
9576
- durationMs: Date.now() - startedAt
9577
- });
9578
- sourceTree = applyOrganization(sourceTree, response.object);
9651
+ label: batches.length > 1 ? `source_tree_organizer_${batchIndex + 1}` : "source_tree_organizer",
9652
+ maxTokens: budget.maxTokens,
9653
+ durationMs: Date.now() - startedAt
9654
+ });
9655
+ organizations.push(response.object);
9656
+ }
9657
+ sourceTree = applyOrganization(sourceTree, mergeOrganizationResults(organizations));
9579
9658
  } catch (error) {
9580
9659
  warnings.push(`Source-tree organizer failed; deterministic tree used (${error instanceof Error ? error.message : String(error)})`);
9581
9660
  }