@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.mjs CHANGED
@@ -8890,6 +8890,8 @@ var ORGANIZABLE_KINDS = [
8890
8890
  "schedule",
8891
8891
  "clause"
8892
8892
  ];
8893
+ var ORGANIZATION_TOP_LEVEL_BATCH_SIZE = 80;
8894
+ var ORGANIZATION_CHILD_CONTEXT_LIMIT = 4;
8893
8895
  var SourceTreeOrganizationSchema = z41.object({
8894
8896
  labels: z41.array(z41.object({
8895
8897
  nodeId: z41.string(),
@@ -8954,7 +8956,7 @@ function cleanText(value, fallback) {
8954
8956
  const text = value?.replace(/\s+/g, " ").trim();
8955
8957
  return text || fallback;
8956
8958
  }
8957
- function compactNode(node) {
8959
+ function compactNode(node, maxText = 700) {
8958
8960
  return {
8959
8961
  id: node.id,
8960
8962
  kind: node.kind,
@@ -8963,20 +8965,89 @@ function compactNode(node) {
8963
8965
  pageStart: node.pageStart,
8964
8966
  pageEnd: node.pageEnd,
8965
8967
  sourceSpanIds: node.sourceSpanIds.slice(0, 8),
8966
- text: (node.textExcerpt ?? node.description).slice(0, 700)
8968
+ text: (node.textExcerpt ?? node.description).slice(0, maxText)
8967
8969
  };
8968
8970
  }
8969
- function buildOrganizationPrompt(sourceTree) {
8970
- const nodes = sourceTree.filter((node) => node.kind !== "document").slice(0, 240).map(compactNode);
8971
+ function nodesByParent(sourceTree) {
8972
+ const byParent = /* @__PURE__ */ new Map();
8973
+ for (const node of sourceTree) {
8974
+ const children = byParent.get(node.parentId) ?? [];
8975
+ children.push(node);
8976
+ byParent.set(node.parentId, children);
8977
+ }
8978
+ for (const children of byParent.values()) {
8979
+ children.sort((left, right) => left.order - right.order || left.id.localeCompare(right.id));
8980
+ }
8981
+ return byParent;
8982
+ }
8983
+ function sourceTreeRootId(sourceTree) {
8984
+ return sourceTree.find((node) => node.kind === "document")?.id;
8985
+ }
8986
+ function organizationBatches(sourceTree) {
8987
+ const byParent = nodesByParent(sourceTree);
8988
+ const rootId = sourceTreeRootId(sourceTree);
8989
+ const topLevelNodes = (byParent.get(rootId) ?? []).filter((node) => node.kind !== "document");
8990
+ if (topLevelNodes.length === 0) {
8991
+ const nodes = sourceTree.filter((node) => node.kind !== "document").slice(0, 240);
8992
+ return [{
8993
+ label: "fallback node prefix because no document root children were found",
8994
+ topLevelNodeIds: nodes.map((node) => node.id),
8995
+ nodes
8996
+ }];
8997
+ }
8998
+ const batches = [];
8999
+ for (let index = 0; index < topLevelNodes.length; index += ORGANIZATION_TOP_LEVEL_BATCH_SIZE) {
9000
+ const topLevelBatch = topLevelNodes.slice(index, index + ORGANIZATION_TOP_LEVEL_BATCH_SIZE);
9001
+ const candidates = /* @__PURE__ */ new Map();
9002
+ for (const node of topLevelBatch) {
9003
+ candidates.set(node.id, node);
9004
+ const childContext = (byParent.get(node.id) ?? []).filter((child) => child.kind !== "text" && child.kind !== "table_cell").slice(0, ORGANIZATION_CHILD_CONTEXT_LIMIT);
9005
+ for (const child of childContext) {
9006
+ candidates.set(child.id, child);
9007
+ }
9008
+ }
9009
+ batches.push({
9010
+ label: `top-level nodes ${index + 1}-${index + topLevelBatch.length} of ${topLevelNodes.length}`,
9011
+ topLevelNodeIds: topLevelBatch.map((node) => node.id),
9012
+ nodes: [...candidates.values()]
9013
+ });
9014
+ }
9015
+ return batches;
9016
+ }
9017
+ function mergeOrganizationResults(results) {
9018
+ const labels = /* @__PURE__ */ new Map();
9019
+ const groups = /* @__PURE__ */ new Map();
9020
+ for (const result of results) {
9021
+ for (const label of result.labels) {
9022
+ labels.set(label.nodeId, { ...labels.get(label.nodeId), ...label });
9023
+ }
9024
+ for (const group of result.groups) {
9025
+ const key = `${group.kind}:${group.childNodeIds.join("|")}`;
9026
+ groups.set(key, group);
9027
+ }
9028
+ }
9029
+ return {
9030
+ labels: [...labels.values()],
9031
+ groups: [...groups.values()]
9032
+ };
9033
+ }
9034
+ function buildOrganizationPrompt(batch) {
9035
+ const nodes = batch.nodes.map((node) => compactNode(node, node.kind === "page" ? 900 : 320));
8971
9036
  return `You organize an insurance document source tree.
8972
9037
 
9038
+ Scope:
9039
+ - ${batch.label}
9040
+ - The provided list is a bounded extraction-time batch. It is not necessarily the whole document.
9041
+ - Top-level page/form candidates in this batch: ${JSON.stringify(batch.topLevelNodeIds)}
9042
+
8973
9043
  Rules:
8974
9044
  - Use only node IDs from the provided list.
8975
9045
  - Do not invent text, page numbers, source spans, limits, or policy facts.
8976
- - 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.
9046
+ - 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.
8977
9047
  - Add concise, human-readable titles to generic text, table, row, and cell nodes when the text makes their role clear.
8978
9048
  - Groups must list existing childNodeIds only.
8979
9049
  - Keep descriptions short and useful for search.
9050
+ - Prefer the document's own form titles, endorsement titles, schedules, declarations headings, and page order over keyword-only guessing.
8980
9051
 
8981
9052
  Source nodes:
8982
9053
  ${JSON.stringify(nodes, null, 2)}
@@ -9016,8 +9087,9 @@ function groupNodeId(documentId, group) {
9016
9087
  }
9017
9088
  function applyOrganization(sourceTree, organization) {
9018
9089
  const byId = new Map(sourceTree.map((node) => [node.id, node]));
9090
+ const labels = new Map(organization.labels.map((label) => [label.nodeId, label]));
9019
9091
  let nextTree = sourceTree.map((node) => {
9020
- const label = organization.labels.find((item) => item.nodeId === node.id);
9092
+ const label = labels.get(node.id);
9021
9093
  if (!label) return node;
9022
9094
  return {
9023
9095
  ...node,
@@ -9026,7 +9098,7 @@ function applyOrganization(sourceTree, organization) {
9026
9098
  description: cleanText(label.description, node.description)
9027
9099
  };
9028
9100
  });
9029
- for (const group of organization.groups.slice(0, 40)) {
9101
+ for (const group of organization.groups) {
9030
9102
  const children = group.childNodeIds.map((id2) => byId.get(id2)).filter((node2) => Boolean(node2));
9031
9103
  if (children.length === 0) continue;
9032
9104
  const parentId = children[0].parentId;
@@ -9208,30 +9280,35 @@ async function runSourceTreeExtraction(params) {
9208
9280
  params.trackUsage(usage, report);
9209
9281
  };
9210
9282
  try {
9211
- const budget = params.resolveBudget("extraction_source_tree", 4096);
9212
- const startedAt = Date.now();
9213
- const response = await safeGenerateObject(
9214
- params.generateObject,
9215
- {
9216
- prompt: buildOrganizationPrompt(sourceTree),
9217
- schema: SourceTreeOrganizationSchema,
9218
- maxTokens: budget.maxTokens,
9283
+ const organizations = [];
9284
+ const batches = organizationBatches(sourceTree);
9285
+ for (const [batchIndex, batch] of batches.entries()) {
9286
+ const budget = params.resolveBudget("extraction_source_tree", 4096);
9287
+ const startedAt = Date.now();
9288
+ const response = await safeGenerateObject(
9289
+ params.generateObject,
9290
+ {
9291
+ prompt: buildOrganizationPrompt(batch),
9292
+ schema: SourceTreeOrganizationSchema,
9293
+ maxTokens: budget.maxTokens,
9294
+ taskKind: "extraction_source_tree",
9295
+ budgetDiagnostics: budget,
9296
+ providerOptions: { ...params.providerOptions, sourceSpans: params.sourceSpans }
9297
+ },
9298
+ {
9299
+ fallback: { labels: [], groups: [] },
9300
+ log: params.log
9301
+ }
9302
+ );
9303
+ localTrack(response.usage, {
9219
9304
  taskKind: "extraction_source_tree",
9220
- budgetDiagnostics: budget,
9221
- providerOptions: { ...params.providerOptions, sourceSpans: params.sourceSpans }
9222
- },
9223
- {
9224
- fallback: { labels: [], groups: [] },
9225
- log: params.log
9226
- }
9227
- );
9228
- localTrack(response.usage, {
9229
- taskKind: "extraction_source_tree",
9230
- label: "source_tree_organizer",
9231
- maxTokens: budget.maxTokens,
9232
- durationMs: Date.now() - startedAt
9233
- });
9234
- sourceTree = applyOrganization(sourceTree, response.object);
9305
+ label: batches.length > 1 ? `source_tree_organizer_${batchIndex + 1}` : "source_tree_organizer",
9306
+ maxTokens: budget.maxTokens,
9307
+ durationMs: Date.now() - startedAt
9308
+ });
9309
+ organizations.push(response.object);
9310
+ }
9311
+ sourceTree = applyOrganization(sourceTree, mergeOrganizationResults(organizations));
9235
9312
  } catch (error) {
9236
9313
  warnings.push(`Source-tree organizer failed; deterministic tree used (${error instanceof Error ? error.message : String(error)})`);
9237
9314
  }