@claritylabs/cl-sdk 3.0.2 → 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(),
@@ -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,20 +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)
9313
9315
  };
9314
9316
  }
9315
- function buildOrganizationPrompt(sourceTree) {
9316
- const nodes = sourceTree.filter((node) => node.kind !== "document").slice(0, 240).map(compactNode);
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()]
9378
+ };
9379
+ }
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.
9323
9393
  - Add concise, human-readable titles to generic text, table, row, and cell nodes when the text makes their role clear.
9324
9394
  - Groups must list existing childNodeIds only.
9325
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.
9326
9397
 
9327
9398
  Source nodes:
9328
9399
  ${JSON.stringify(nodes, null, 2)}
@@ -9362,8 +9433,9 @@ function groupNodeId(documentId, group) {
9362
9433
  }
9363
9434
  function applyOrganization(sourceTree, organization) {
9364
9435
  const byId = new Map(sourceTree.map((node) => [node.id, node]));
9436
+ const labels = new Map(organization.labels.map((label) => [label.nodeId, label]));
9365
9437
  let nextTree = sourceTree.map((node) => {
9366
- const label = organization.labels.find((item) => item.nodeId === node.id);
9438
+ const label = labels.get(node.id);
9367
9439
  if (!label) return node;
9368
9440
  return {
9369
9441
  ...node,
@@ -9372,7 +9444,7 @@ function applyOrganization(sourceTree, organization) {
9372
9444
  description: cleanText(label.description, node.description)
9373
9445
  };
9374
9446
  });
9375
- for (const group of organization.groups.slice(0, 40)) {
9447
+ for (const group of organization.groups) {
9376
9448
  const children = group.childNodeIds.map((id2) => byId.get(id2)).filter((node2) => Boolean(node2));
9377
9449
  if (children.length === 0) continue;
9378
9450
  const parentId = children[0].parentId;
@@ -9554,30 +9626,35 @@ async function runSourceTreeExtraction(params) {
9554
9626
  params.trackUsage(usage, report);
9555
9627
  };
9556
9628
  try {
9557
- const budget = params.resolveBudget("extraction_source_tree", 4096);
9558
- const startedAt = Date.now();
9559
- const response = await safeGenerateObject(
9560
- params.generateObject,
9561
- {
9562
- prompt: buildOrganizationPrompt(sourceTree),
9563
- schema: SourceTreeOrganizationSchema,
9564
- 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, {
9565
9650
  taskKind: "extraction_source_tree",
9566
- budgetDiagnostics: budget,
9567
- providerOptions: { ...params.providerOptions, sourceSpans: params.sourceSpans }
9568
- },
9569
- {
9570
- fallback: { labels: [], groups: [] },
9571
- log: params.log
9572
- }
9573
- );
9574
- localTrack(response.usage, {
9575
- taskKind: "extraction_source_tree",
9576
- label: "source_tree_organizer",
9577
- maxTokens: budget.maxTokens,
9578
- durationMs: Date.now() - startedAt
9579
- });
9580
- 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));
9581
9658
  } catch (error) {
9582
9659
  warnings.push(`Source-tree organizer failed; deterministic tree used (${error instanceof Error ? error.message : String(error)})`);
9583
9660
  }