@claritylabs/cl-sdk 3.0.33 → 3.1.2

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
@@ -3235,6 +3235,12 @@ function moneyAmount(value) {
3235
3235
  function normalizeLabel(value) {
3236
3236
  return normalizeWhitespace3(value ?? "").toLowerCase();
3237
3237
  }
3238
+ function isGenericColumnLabel(value) {
3239
+ return /^column\s+\d+$/i.test(cleanValue(value) ?? "");
3240
+ }
3241
+ function isHeaderRow(row) {
3242
+ return row.metadata?.isHeader === true || row.metadata?.isHeader === "true";
3243
+ }
3238
3244
  var OPERATIONAL_COVERAGE_TERM_KINDS = /* @__PURE__ */ new Set([
3239
3245
  "each_claim_limit",
3240
3246
  "each_occurrence_limit",
@@ -3255,6 +3261,7 @@ function termKind(label, value) {
3255
3261
  if (/\bpremium\b/.test(text)) return "premium";
3256
3262
  if (/\bsub[-\s]?limit\b/.test(text)) return "sublimit";
3257
3263
  if (/\baggregate\b/.test(text)) return "aggregate_limit";
3264
+ if (/\beach\s+proceeding|per\s+proceeding\b/.test(text)) return "sublimit";
3258
3265
  if (/\beach\s+claim|per\s+claim\b/.test(text)) return "each_claim_limit";
3259
3266
  if (/\beach\s+occurrence|per\s+occurrence\b/.test(text)) return "each_occurrence_limit";
3260
3267
  if (/\beach\s+loss|per\s+loss\b/.test(text)) return "each_loss_limit";
@@ -3281,9 +3288,13 @@ function isNameCell(label, value) {
3281
3288
  const normalizedLabel = normalizeLabel(label);
3282
3289
  const normalizedValue = normalizeLabel(value);
3283
3290
  if (!value || moneyAmount(value) !== void 0) return false;
3291
+ if (/^item\s+\d+[.)]?\s*limits?\s+of\s+liability\b/.test(normalizedValue)) return false;
3284
3292
  if (/\b(coverage|coverage part|insuring agreement|description|item|name)\b/.test(normalizedLabel)) {
3285
3293
  return true;
3286
3294
  }
3295
+ if (/\b(sub[-\s]?limit|aggregate(?:\s+policy)?\s+limit|limit\s+of\s+liability)\b/.test(normalizedLabel) && /\b[a-z][a-z0-9&/ -]{2,}\b/.test(normalizedValue) && !/\bcoverage\s+part\s+[a-z]\)?$/.test(normalizedValue)) {
3296
+ return true;
3297
+ }
3287
3298
  if (/^column\s+1$/.test(normalizedLabel) && !/^(item\s+\d+|nwc-|iso-|cg |il |form\b|page\b)/i.test(normalizedValue)) {
3288
3299
  return true;
3289
3300
  }
@@ -3302,13 +3313,32 @@ function childMap(nodes) {
3302
3313
  for (const group of children.values()) group.sort((left, right) => left.order - right.order);
3303
3314
  return children;
3304
3315
  }
3305
- function cellRows(row, children) {
3316
+ function rawCellRows(row, children) {
3306
3317
  return (children.get(row.id) ?? []).filter((child) => child.kind === "table_cell").map((cell) => ({
3307
3318
  label: cleanValue(cell.title) ?? "Value",
3308
3319
  value: cleanValue(cell.textExcerpt ?? cell.description ?? cell.title) ?? "",
3309
3320
  node: cell
3310
3321
  })).filter((cell) => cell.value);
3311
3322
  }
3323
+ function headerLabelsForRow(row, children) {
3324
+ if (!row.parentId) return [];
3325
+ const labels = [];
3326
+ const siblingRows = (children.get(row.parentId) ?? []).filter((candidate) => candidate.kind === "table_row" && candidate.order < row.order).sort((left, right) => left.order - right.order);
3327
+ for (const sibling of siblingRows) {
3328
+ if (!isHeaderRow(sibling)) continue;
3329
+ for (const [index, cell] of rawCellRows(sibling, children).entries()) {
3330
+ const label = cleanValue(cell.value) ?? cleanValue(cell.label);
3331
+ if (label && !isGenericColumnLabel(label)) labels[index] = label;
3332
+ }
3333
+ }
3334
+ return labels;
3335
+ }
3336
+ function cellRows(row, children, headerLabels = []) {
3337
+ return rawCellRows(row, children).map((cell, index) => ({
3338
+ ...cell,
3339
+ label: isGenericColumnLabel(cell.label) && headerLabels[index] ? headerLabels[index] : cell.label
3340
+ }));
3341
+ }
3312
3342
  function directChildren(parent, children) {
3313
3343
  return children.get(parent.id) ?? [];
3314
3344
  }
@@ -3361,8 +3391,9 @@ function relabelGenericTerm(term, label) {
3361
3391
  };
3362
3392
  }
3363
3393
  function termFromCell(params) {
3364
- const value = cleanValue(params.value);
3394
+ const value = cleanCoverageTermValue(params.value);
3365
3395
  if (!value) return void 0;
3396
+ if (isRejectedCoverageTermValue(params.label, value)) return void 0;
3366
3397
  const nodes = [params.row, params.cell].filter((node) => Boolean(node));
3367
3398
  const kind = termKind(params.label, value);
3368
3399
  const amount = moneyAmount(value);
@@ -3375,20 +3406,38 @@ function termFromCell(params) {
3375
3406
  ...sourceIds(nodes)
3376
3407
  };
3377
3408
  }
3409
+ function cleanCoverageTermValue(value) {
3410
+ return cleanValue(value)?.replace(/\s+\/\s*$/, "").trim();
3411
+ }
3412
+ function isRejectedCoverageTermValue(label, value) {
3413
+ if (/\bshown\s+in\s+item\s*\d+\b/i.test(value) && moneyAmount(value) === void 0) return true;
3414
+ if (/\b(does not afford coverage|doesn't afford coverage|no coverage|remains excluded|is excluded|are excluded|shall not cover|will not cover)\b/i.test(value) && moneyAmount(value) === void 0) {
3415
+ return true;
3416
+ }
3417
+ if (/^for:\s*\(\d+\)/i.test(label) && moneyAmount(value) === void 0) return true;
3418
+ if (value.length > 80 && /\b(exclusion|excluded|shall not|will not|does not|failure to)\b/i.test(value) && moneyAmount(value) === void 0) return true;
3419
+ return false;
3420
+ }
3378
3421
  function termsFromRow(row, children) {
3379
- const cells = cellRows(row, children);
3422
+ const cells = cellRows(row, children, headerLabelsForRow(row, children));
3380
3423
  if (cells.length > 0) {
3381
3424
  const pairedTerms = [];
3425
+ const pairedIndexes = /* @__PURE__ */ new Set();
3382
3426
  for (const [index, cell] of cells.entries()) {
3383
3427
  const next = cells[index + 1];
3384
3428
  if (!next) continue;
3429
+ if (!isGenericColumnLabel(cell.label) && isNameCell(cell.label, cell.value)) continue;
3385
3430
  if (!isCoverageTermLabel(cell.value)) continue;
3386
3431
  if (isCoverageTermLabel(next.value) && moneyAmount(next.value) === void 0) continue;
3387
3432
  const term = termFromCell({ row, cell: next.node, label: cell.value, value: next.value });
3388
- if (term) pairedTerms.push(term);
3433
+ if (term) {
3434
+ pairedTerms.push(term);
3435
+ pairedIndexes.add(index);
3436
+ pairedIndexes.add(index + 1);
3437
+ }
3389
3438
  }
3390
- if (pairedTerms.length > 0) return pairedTerms;
3391
- return cells.filter((cell) => isValueCell(cell.label, cell.value)).map((cell) => termFromCell({ row, cell: cell.node, label: cell.label, value: cell.value })).filter((term) => Boolean(term));
3439
+ const valueTerms = cells.filter((_, index) => !pairedIndexes.has(index)).filter((cell) => isValueCell(cell.label, cell.value)).map((cell) => termFromCell({ row, cell: cell.node, label: cell.label, value: cell.value })).filter((term) => Boolean(term));
3440
+ return [...pairedTerms, ...valueTerms];
3392
3441
  }
3393
3442
  const text = normalizeWhitespace3(row.textExcerpt ?? row.description ?? nodeText(row));
3394
3443
  const terms = [];
@@ -3414,11 +3463,11 @@ function termsFromRow(row, children) {
3414
3463
  return terms;
3415
3464
  }
3416
3465
  function nameFromRow(row, children) {
3417
- const declarationName = declarationCoverageNameFromRow(row, children);
3418
- if (declarationName) return declarationName;
3419
- const cells = cellRows(row, children);
3466
+ const cells = cellRows(row, children, headerLabelsForRow(row, children));
3420
3467
  const named = cells.find((cell) => isNameCell(cell.label, cell.value));
3421
3468
  if (named) return cleanValue(named.value);
3469
+ const declarationName = declarationCoverageNameFromRow(row, children);
3470
+ if (declarationName) return declarationName;
3422
3471
  return coverageNameFromRow(row.textExcerpt ?? row.description ?? nodeText(row));
3423
3472
  }
3424
3473
  function legacyLimit(terms) {
@@ -3451,7 +3500,7 @@ function isOperationalCoverageRow(coverage) {
3451
3500
  if (coverage.name.split(/\s+/).length > 16 && !/\b(coverage|liability|sub[-\s]?limit|aggregate|each\s+(claim|loss|occurrence)|limit)\b/i.test(coverage.name)) {
3452
3501
  return false;
3453
3502
  }
3454
- return /\b(coverage|coverage part|liability|sub[-\s]?limit|aggregate|each\s+(claim|loss|occurrence)|bricking|cyber|privacy|media|regulatory|defense|ai\/ml|errors?\s*&?\s*omissions|technology)\b/i.test(coverage.name);
3503
+ return /\b(coverage|coverage part|liability|sub[-\s]?limit|aggregate|each\s+(claim|loss|occurrence|proceeding)|bricking|cyber|privacy|media|regulatory|defense|fraud|social engineering|ai\/ml|errors?\s*&?\s*omissions|technology)\b/i.test(coverage.name);
3455
3504
  }
3456
3505
  function uniqueTerms(terms) {
3457
3506
  const seen = /* @__PURE__ */ new Set();
@@ -3465,7 +3514,7 @@ function uniqueTerms(terms) {
3465
3514
  return result;
3466
3515
  }
3467
3516
  function coverageFromTableRow(row, children, byId) {
3468
- if (row.metadata?.isHeader === true || row.metadata?.isHeader === "true") return void 0;
3517
+ if (isHeaderRow(row)) return void 0;
3469
3518
  const name = nameFromRow(row, children);
3470
3519
  const terms = uniqueTerms(termsFromRow(row, children));
3471
3520
  if (!name || terms.length === 0) return void 0;
@@ -12664,6 +12713,55 @@ var ApplicationFieldSchema = z42.object({
12664
12713
  acroFormName: z42.string().optional().describe("Native PDF AcroForm field name when available"),
12665
12714
  validationStatus: z42.enum(["valid", "needs_review", "unsupported", "missing"]).optional()
12666
12715
  });
12716
+ var ApplicationQuestionConditionSchema = z42.object({
12717
+ dependsOn: z42.string(),
12718
+ operator: z42.enum(["equals", "not_equals", "in", "not_in", "exists"]).optional(),
12719
+ value: z42.string().optional(),
12720
+ whenValue: z42.string().optional(),
12721
+ values: z42.array(z42.string()).optional()
12722
+ });
12723
+ var ApplicationRepeatSchema = z42.object({
12724
+ min: z42.number().int().nonnegative().optional(),
12725
+ max: z42.number().int().positive().optional(),
12726
+ label: z42.string().optional()
12727
+ });
12728
+ var ApplicationQuestionNodeSchema = z42.lazy(
12729
+ () => z42.object({
12730
+ id: z42.string(),
12731
+ nodeType: z42.enum(["group", "question", "repeat_group", "table"]),
12732
+ fieldId: z42.string().optional(),
12733
+ fieldPath: z42.string().optional(),
12734
+ parentId: z42.string().optional(),
12735
+ order: z42.number().int().nonnegative().optional(),
12736
+ label: z42.string(),
12737
+ section: z42.string().optional(),
12738
+ fieldType: FieldTypeSchema.optional(),
12739
+ required: z42.boolean().optional(),
12740
+ prompt: z42.string().optional(),
12741
+ options: z42.array(z42.string()).optional(),
12742
+ columns: z42.array(z42.string()).optional(),
12743
+ condition: ApplicationQuestionConditionSchema.optional(),
12744
+ repeat: ApplicationRepeatSchema.optional(),
12745
+ children: z42.array(ApplicationQuestionNodeSchema).optional()
12746
+ })
12747
+ );
12748
+ var ApplicationQuestionGraphSchema = z42.object({
12749
+ id: z42.string(),
12750
+ version: z42.string(),
12751
+ title: z42.string().optional(),
12752
+ applicationType: z42.string().nullable().optional(),
12753
+ source: z42.enum(["pdf", "manual", "imported", "generated"]).default("generated"),
12754
+ rootNodeIds: z42.array(z42.string()).optional(),
12755
+ nodes: z42.array(ApplicationQuestionNodeSchema)
12756
+ });
12757
+ var ApplicationTemplateSchema = z42.object({
12758
+ id: z42.string(),
12759
+ version: z42.string(),
12760
+ title: z42.string(),
12761
+ applicationType: z42.string().nullable().optional(),
12762
+ questionGraph: ApplicationQuestionGraphSchema,
12763
+ fields: z42.array(ApplicationFieldSchema).optional()
12764
+ });
12667
12765
  var ApplicationClassifyResultSchema = z42.object({
12668
12766
  isApplication: z42.boolean(),
12669
12767
  confidence: z42.number().min(0).max(1),
@@ -12761,16 +12859,67 @@ var ApplicationQualityReportSchema = z42.object({
12761
12859
  emailReview: ApplicationEmailReviewSchema.optional(),
12762
12860
  qualityGateStatus: QualityGateStatusSchema
12763
12861
  });
12862
+ var ApplicationContextProposalSchema = z42.object({
12863
+ id: z42.string(),
12864
+ fieldId: z42.string().optional(),
12865
+ key: z42.string(),
12866
+ value: z42.string(),
12867
+ category: z42.string(),
12868
+ source: z42.enum(["application", "user", "lookup", "policy", "email", "chat", "imessage", "mcp"]),
12869
+ confidence: z42.enum(["confirmed", "high", "medium", "low"]),
12870
+ sourceSpanIds: z42.array(z42.string()).optional(),
12871
+ userSourceSpanIds: z42.array(z42.string()).optional()
12872
+ });
12873
+ var ApplicationPacketAnswerSchema = z42.object({
12874
+ fieldId: z42.string(),
12875
+ label: z42.string(),
12876
+ section: z42.string(),
12877
+ value: z42.string(),
12878
+ source: z42.string(),
12879
+ confidence: z42.enum(["confirmed", "high", "medium", "low"]).optional(),
12880
+ sourceSpanIds: z42.array(z42.string()).optional(),
12881
+ userSourceSpanIds: z42.array(z42.string()).optional()
12882
+ });
12883
+ var ApplicationPacketSchema = z42.object({
12884
+ id: z42.string(),
12885
+ applicationId: z42.string(),
12886
+ title: z42.string(),
12887
+ status: z42.enum(["draft", "broker_ready", "submitted"]),
12888
+ answers: z42.array(ApplicationPacketAnswerSchema),
12889
+ missingFieldIds: z42.array(z42.string()),
12890
+ qualityReport: ApplicationQualityReportSchema,
12891
+ submissionNotes: z42.string().optional(),
12892
+ createdAt: z42.number()
12893
+ });
12764
12894
  var ApplicationStateSchema = z42.object({
12765
12895
  id: z42.string(),
12766
12896
  pdfBase64: z42.string().optional().describe("Original PDF, omitted after extraction"),
12897
+ templateId: z42.string().optional(),
12898
+ templateVersion: z42.string().optional(),
12899
+ templateSnapshot: ApplicationTemplateSchema.optional(),
12767
12900
  title: z42.string().optional(),
12768
12901
  applicationType: z42.string().nullable().optional(),
12902
+ questionGraph: ApplicationQuestionGraphSchema.optional(),
12769
12903
  fields: z42.array(ApplicationFieldSchema),
12770
12904
  batches: z42.array(z42.array(z42.string())).optional(),
12771
12905
  currentBatchIndex: z42.number().default(0),
12906
+ contextProposals: z42.array(ApplicationContextProposalSchema).optional(),
12907
+ packet: ApplicationPacketSchema.optional(),
12772
12908
  qualityReport: ApplicationQualityReportSchema.optional(),
12773
- status: z42.enum(["classifying", "extracting", "auto_filling", "batching", "collecting", "confirming", "mapping", "complete"]),
12909
+ status: z42.enum([
12910
+ "classifying",
12911
+ "extracting",
12912
+ "auto_filling",
12913
+ "batching",
12914
+ "collecting",
12915
+ "confirming",
12916
+ "mapping",
12917
+ "broker_review",
12918
+ "packet_ready",
12919
+ "submitted",
12920
+ "cancelled",
12921
+ "complete"
12922
+ ]),
12774
12923
  createdAt: z42.number(),
12775
12924
  updatedAt: z42.number()
12776
12925
  });
@@ -13469,7 +13618,7 @@ function planReplyActions(input) {
13469
13618
  parseAnswers: input.intent.hasAnswers && hasCurrentFields,
13470
13619
  runLookup: hasLookupRequests && input.hasDocumentStore,
13471
13620
  answerQuestion: Boolean(input.intent.questionText) && (input.intent.primaryIntent === "question" || input.intent.primaryIntent === "mixed"),
13472
- advanceBatch: hasCurrentFields && input.currentBatchFields.every((field) => !isUnfilled(field)),
13621
+ advanceBatch: hasCurrentFields && input.currentBatchFields.every((field) => !isUnfilled(field)) || !hasCurrentFields && nextBatchNeedsAnswers,
13473
13622
  generateNextEmail: nextBatchNeedsAnswers
13474
13623
  };
13475
13624
  }
@@ -13508,12 +13657,287 @@ function isHighValueLookupField(field) {
13508
13657
  ].some((term) => text.includes(term));
13509
13658
  }
13510
13659
 
13660
+ // src/application/question-graph.ts
13661
+ function buildQuestionGraphFromFields(fields, options) {
13662
+ const sectionNodes = /* @__PURE__ */ new Map();
13663
+ const nodes = [];
13664
+ for (const [index, field] of fields.entries()) {
13665
+ const sectionId = stableNodeId(["section", field.section]);
13666
+ let sectionNode = sectionNodes.get(sectionId);
13667
+ if (!sectionNode) {
13668
+ sectionNode = {
13669
+ id: sectionId,
13670
+ nodeType: "group",
13671
+ label: field.section,
13672
+ order: sectionNodes.size,
13673
+ children: []
13674
+ };
13675
+ sectionNodes.set(sectionId, sectionNode);
13676
+ nodes.push(sectionNode);
13677
+ }
13678
+ const child = {
13679
+ id: field.fieldAnchorId ?? stableNodeId(["field", field.section, field.id || field.label]),
13680
+ nodeType: field.fieldType === "table" ? "table" : "question",
13681
+ fieldId: field.id,
13682
+ fieldPath: `${field.section}.${field.id}`,
13683
+ parentId: sectionId,
13684
+ order: index,
13685
+ label: field.label,
13686
+ section: field.section,
13687
+ fieldType: field.fieldType,
13688
+ required: field.required,
13689
+ options: field.options,
13690
+ columns: field.columns,
13691
+ condition: field.condition ? {
13692
+ dependsOn: field.condition.dependsOn,
13693
+ operator: "equals",
13694
+ value: field.condition.whenValue,
13695
+ whenValue: field.condition.whenValue
13696
+ } : void 0
13697
+ };
13698
+ sectionNode.children = [...sectionNode.children ?? [], child];
13699
+ }
13700
+ return normalizeApplicationQuestionGraph({
13701
+ id: options.id,
13702
+ version: options.version ?? "v1",
13703
+ title: options.title,
13704
+ applicationType: options.applicationType,
13705
+ source: options.source ?? "generated",
13706
+ rootNodeIds: nodes.map((node) => node.id),
13707
+ nodes
13708
+ });
13709
+ }
13710
+ function normalizeApplicationQuestionGraph(graph) {
13711
+ const normalizedNodes = graph.nodes.map((node, index) => normalizeNode(node, void 0, index)).sort(compareNodes);
13712
+ return {
13713
+ ...graph,
13714
+ rootNodeIds: graph.rootNodeIds?.length ? graph.rootNodeIds : normalizedNodes.map((node) => node.id),
13715
+ nodes: normalizedNodes
13716
+ };
13717
+ }
13718
+ function flattenQuestionGraph(graph) {
13719
+ const fields = [];
13720
+ for (const node of graph.nodes.sort(compareNodes)) {
13721
+ collectFields(node, fields);
13722
+ }
13723
+ return fields;
13724
+ }
13725
+ function getActiveApplicationFields(state) {
13726
+ const valueByFieldId = new Map(
13727
+ state.fields.filter((field) => field.value !== void 0 && field.value.trim() !== "").map((field) => [field.id, field.value ?? ""])
13728
+ );
13729
+ const graphConditions = /* @__PURE__ */ new Map();
13730
+ for (const node of state.questionGraph?.nodes ?? []) {
13731
+ collectNodeConditions(node, graphConditions);
13732
+ }
13733
+ return state.fields.filter((field) => {
13734
+ const graphCondition = graphConditions.get(field.id);
13735
+ return isConditionSatisfied(field.condition, valueByFieldId) && isQuestionConditionSatisfied(graphCondition, valueByFieldId);
13736
+ });
13737
+ }
13738
+ function getNextApplicationQuestions(state, limit = 8) {
13739
+ const activeUnfilled = getActiveApplicationFields(state).filter((field) => !field.value);
13740
+ if (activeUnfilled.length === 0) return [];
13741
+ const currentBatchIds = state.batches?.[state.currentBatchIndex] ?? [];
13742
+ const currentBatchFields = activeUnfilled.filter((field) => currentBatchIds.includes(field.id));
13743
+ return (currentBatchFields.length > 0 ? currentBatchFields : activeUnfilled).slice(0, limit);
13744
+ }
13745
+ function normalizeNode(node, parentId, index) {
13746
+ const children = node.children?.map((child, childIndex) => normalizeNode(child, node.id, childIndex));
13747
+ return {
13748
+ ...node,
13749
+ parentId: node.parentId ?? parentId,
13750
+ order: node.order ?? index,
13751
+ fieldPath: node.fieldPath ?? (node.fieldId ? [node.section, node.fieldId].filter(Boolean).join(".") : void 0),
13752
+ children
13753
+ };
13754
+ }
13755
+ function collectFields(node, fields) {
13756
+ if ((node.nodeType === "question" || node.nodeType === "table") && node.fieldId) {
13757
+ fields.push({
13758
+ id: node.fieldId,
13759
+ label: node.label,
13760
+ section: node.section ?? "General",
13761
+ fieldType: node.fieldType ?? (node.nodeType === "table" ? "table" : "text"),
13762
+ required: node.required ?? false,
13763
+ options: node.options,
13764
+ columns: node.columns,
13765
+ condition: node.condition ? {
13766
+ dependsOn: node.condition.dependsOn,
13767
+ whenValue: node.condition.value ?? node.condition.whenValue ?? ""
13768
+ } : void 0,
13769
+ fieldAnchorId: node.id
13770
+ });
13771
+ }
13772
+ for (const child of node.children ?? []) {
13773
+ collectFields(child, fields);
13774
+ }
13775
+ }
13776
+ function collectNodeConditions(node, conditions) {
13777
+ if (node.fieldId && node.condition) {
13778
+ conditions.set(node.fieldId, node.condition);
13779
+ }
13780
+ for (const child of node.children ?? []) {
13781
+ collectNodeConditions(child, conditions);
13782
+ }
13783
+ }
13784
+ function isConditionSatisfied(condition, valueByFieldId) {
13785
+ if (!condition) return true;
13786
+ const current = valueByFieldId.get(condition.dependsOn);
13787
+ return normalizeValue(current) === normalizeValue(condition.whenValue);
13788
+ }
13789
+ function isQuestionConditionSatisfied(condition, valueByFieldId) {
13790
+ if (!condition) return true;
13791
+ const current = valueByFieldId.get(condition.dependsOn);
13792
+ const expected = condition.value ?? condition.whenValue;
13793
+ const values = condition.values ?? (expected !== void 0 ? [expected] : []);
13794
+ switch (condition.operator) {
13795
+ case "exists":
13796
+ return current !== void 0 && current.trim() !== "";
13797
+ case "not_equals":
13798
+ return normalizeValue(current) !== normalizeValue(expected);
13799
+ case "in":
13800
+ return values.map(normalizeValue).includes(normalizeValue(current));
13801
+ case "not_in":
13802
+ return !values.map(normalizeValue).includes(normalizeValue(current));
13803
+ case "equals":
13804
+ default:
13805
+ return normalizeValue(current) === normalizeValue(expected);
13806
+ }
13807
+ }
13808
+ function compareNodes(a, b) {
13809
+ return (a.order ?? 0) - (b.order ?? 0) || a.id.localeCompare(b.id);
13810
+ }
13811
+ function normalizeValue(value) {
13812
+ return (value ?? "").trim().toLowerCase();
13813
+ }
13814
+ function stableNodeId(parts) {
13815
+ return parts.join(":").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "node";
13816
+ }
13817
+
13818
+ // src/application/intake.ts
13819
+ function extractQuestionGraphFromFields(fields, options) {
13820
+ return buildQuestionGraphFromFields(fields, options);
13821
+ }
13822
+ function createApplicationRun(params) {
13823
+ const now = params.now ?? Date.now();
13824
+ const graph = normalizeApplicationQuestionGraph(params.template.questionGraph);
13825
+ const fields = params.template.fields?.length ? params.template.fields : flattenQuestionGraph(graph);
13826
+ return {
13827
+ id: params.applicationId,
13828
+ templateId: params.template.id,
13829
+ templateVersion: params.template.version,
13830
+ templateSnapshot: params.template,
13831
+ title: params.template.title,
13832
+ applicationType: params.template.applicationType,
13833
+ questionGraph: graph,
13834
+ fields,
13835
+ currentBatchIndex: 0,
13836
+ status: "collecting",
13837
+ createdAt: now,
13838
+ updatedAt: now
13839
+ };
13840
+ }
13841
+ function planNextApplicationQuestions(state, limit) {
13842
+ const fields = getNextApplicationQuestions(state, limit);
13843
+ return {
13844
+ status: fields.length === 0 ? "complete" : "needs_answers",
13845
+ fieldIds: fields.map((field) => field.id),
13846
+ fields
13847
+ };
13848
+ }
13849
+ function applyApplicationAnswers(state, answers, now = Date.now()) {
13850
+ const answerByFieldId = new Map(answers.map((answer) => [answer.fieldId, answer]));
13851
+ const fields = state.fields.map((field) => {
13852
+ const answer = answerByFieldId.get(field.id);
13853
+ if (!answer) return field;
13854
+ return {
13855
+ ...field,
13856
+ value: answer.value,
13857
+ source: answer.source ?? "user",
13858
+ confidence: answer.confidence ?? "confirmed",
13859
+ sourceSpanIds: answer.sourceSpanIds ?? field.sourceSpanIds,
13860
+ userSourceSpanIds: answer.userSourceSpanIds ?? field.userSourceSpanIds,
13861
+ validationStatus: "valid"
13862
+ };
13863
+ });
13864
+ const nextState = {
13865
+ ...state,
13866
+ fields,
13867
+ updatedAt: now
13868
+ };
13869
+ const nextQuestions = planNextApplicationQuestions(nextState);
13870
+ return {
13871
+ ...nextState,
13872
+ status: nextQuestions.status === "complete" ? "confirming" : nextState.status,
13873
+ qualityReport: buildApplicationQualityReport(nextState)
13874
+ };
13875
+ }
13876
+ function proposeContextWrites(state) {
13877
+ return getActiveApplicationFields(state).filter((field) => field.value && field.confidence && field.confidence !== "low").map((field) => ({
13878
+ id: `${state.id}:${field.id}:context`,
13879
+ fieldId: field.id,
13880
+ key: stableContextKey(field),
13881
+ value: field.value ?? "",
13882
+ category: field.section,
13883
+ source: field.source?.startsWith("lookup:") ? "lookup" : "application",
13884
+ confidence: field.confidence ?? "medium",
13885
+ sourceSpanIds: field.sourceSpanIds,
13886
+ userSourceSpanIds: field.userSourceSpanIds
13887
+ }));
13888
+ }
13889
+ function buildApplicationPacket(state, options = {}) {
13890
+ const qualityReport = buildApplicationQualityReport(state);
13891
+ const activeFields = getActiveApplicationFields(state);
13892
+ const answers = activeFields.filter((field) => field.value).map((field) => ({
13893
+ fieldId: field.id,
13894
+ label: field.label,
13895
+ section: field.section,
13896
+ value: field.value ?? "",
13897
+ source: field.source ?? "unknown",
13898
+ confidence: field.confidence,
13899
+ sourceSpanIds: field.sourceSpanIds,
13900
+ userSourceSpanIds: field.userSourceSpanIds
13901
+ }));
13902
+ const missingFieldIds = activeFields.filter((field) => field.required && !field.value).map((field) => field.id);
13903
+ return {
13904
+ id: `${state.id}:packet`,
13905
+ applicationId: state.id,
13906
+ title: state.title ?? state.applicationType ?? "Insurance Application",
13907
+ status: qualityReport.qualityGateStatus === "failed" || missingFieldIds.length > 0 ? "draft" : "broker_ready",
13908
+ answers,
13909
+ missingFieldIds,
13910
+ qualityReport,
13911
+ submissionNotes: options.submissionNotes,
13912
+ createdAt: options.now ?? Date.now()
13913
+ };
13914
+ }
13915
+ function validateApplicationPacket(packet) {
13916
+ const issues = [...packet.qualityReport.issues];
13917
+ if (packet.missingFieldIds.length > 0) {
13918
+ issues.push({
13919
+ code: "packet_missing_required_answers",
13920
+ severity: "blocking",
13921
+ message: "Packet still has required unanswered application fields."
13922
+ });
13923
+ }
13924
+ return {
13925
+ ...packet.qualityReport,
13926
+ issues,
13927
+ qualityGateStatus: issues.some((issue) => issue.severity === "blocking") ? "failed" : packet.qualityReport.qualityGateStatus
13928
+ };
13929
+ }
13930
+ function stableContextKey(field) {
13931
+ return `${field.section}.${field.label}`.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
13932
+ }
13933
+
13511
13934
  // src/application/coordinator.ts
13512
13935
  function createApplicationPipeline(config) {
13513
13936
  const {
13514
13937
  generateText,
13515
13938
  generateObject,
13516
13939
  applicationStore,
13940
+ templateStore,
13517
13941
  documentStore,
13518
13942
  memoryStore,
13519
13943
  backfillProvider,
@@ -13550,11 +13974,18 @@ function createApplicationPipeline(config) {
13550
13974
  const applicationProviderOptions = input.sourceSpans?.length ? { ...providerOptions, sourceSpans: input.sourceSpans } : providerOptions;
13551
13975
  const id = input.applicationId ?? `app-${Date.now()}`;
13552
13976
  const now = Date.now();
13977
+ if (input.template) {
13978
+ await templateStore?.saveTemplate(input.template);
13979
+ }
13553
13980
  let state = {
13554
13981
  id,
13982
+ templateId: input.template?.id,
13983
+ templateVersion: input.template?.version,
13984
+ templateSnapshot: input.template,
13555
13985
  pdfBase64: void 0,
13556
13986
  title: void 0,
13557
13987
  applicationType: null,
13988
+ questionGraph: input.questionGraph ?? input.template?.questionGraph,
13558
13989
  fields: [],
13559
13990
  qualityReport: void 0,
13560
13991
  batches: void 0,
@@ -13614,6 +14045,12 @@ function createApplicationPipeline(config) {
13614
14045
  return { state, tokenUsage: totalUsage, reviewReport: state.qualityReport };
13615
14046
  }
13616
14047
  state.fields = fields;
14048
+ state.questionGraph = input.questionGraph ?? input.template?.questionGraph ?? buildQuestionGraphFromFields(fields, {
14049
+ id: `${id}:graph`,
14050
+ title: classifyResult.applicationType ?? void 0,
14051
+ applicationType: classifyResult.applicationType,
14052
+ source: "pdf"
14053
+ });
13617
14054
  state.title = classifyResult.applicationType ?? void 0;
13618
14055
  state.status = "auto_filling";
13619
14056
  state.updatedAt = Date.now();
@@ -13634,8 +14071,10 @@ function createApplicationPipeline(config) {
13634
14071
  if (field && !field.value && pa.relevance > 0.8) {
13635
14072
  field.value = pa.value;
13636
14073
  field.source = `backfill: ${pa.source}`;
13637
- field.confidence = "high";
13638
- field.validationStatus = "needs_review";
14074
+ field.confidence = pa.confidence ?? "high";
14075
+ field.validationStatus = pa.sourceSpanIds?.length ? "valid" : "needs_review";
14076
+ field.sourceSpanIds = pa.sourceSpanIds;
14077
+ field.userSourceSpanIds = pa.userSourceSpanIds;
13639
14078
  }
13640
14079
  }
13641
14080
  } catch (e) {
@@ -13685,7 +14124,18 @@ function createApplicationPipeline(config) {
13685
14124
  try {
13686
14125
  const searchPromises = workflowPlan.documentSearchFields.map(
13687
14126
  (f) => limit(async () => {
13688
- await memoryStore.search(f.label, { limit: 3 });
14127
+ const chunks = await memoryStore.search(`${f.section} ${f.label}`, { limit: 3 });
14128
+ const match = selectMemoryBackfillMatch(f, chunks);
14129
+ if (match) {
14130
+ const field = state.fields.find((candidate) => candidate.id === f.id);
14131
+ if (field && !field.value) {
14132
+ field.value = match.value;
14133
+ field.source = match.source;
14134
+ field.confidence = match.confidence;
14135
+ field.validationStatus = match.sourceSpanIds.length > 0 ? "valid" : "needs_review";
14136
+ field.sourceSpanIds = match.sourceSpanIds.length > 0 ? match.sourceSpanIds : void 0;
14137
+ }
14138
+ }
13689
14139
  })
13690
14140
  );
13691
14141
  await Promise.all(searchPromises);
@@ -13705,7 +14155,7 @@ function createApplicationPipeline(config) {
13705
14155
  hasDocumentStore: false,
13706
14156
  hasMemoryStore: false
13707
14157
  });
13708
- const unfilledFields = workflowPlan.unfilledFields;
14158
+ const unfilledFields = getActiveApplicationFields(state).filter((field) => !field.value);
13709
14159
  if (workflowPlan.runBatching) {
13710
14160
  onProgress?.(`Batching ${unfilledFields.length} remaining questions...`);
13711
14161
  state.status = "batching";
@@ -13727,6 +14177,7 @@ function createApplicationPipeline(config) {
13727
14177
  } else {
13728
14178
  state.status = "confirming";
13729
14179
  }
14180
+ state.contextProposals = proposeContextWrites(state);
13730
14181
  state.qualityReport = buildApplicationQualityReport(state);
13731
14182
  state.updatedAt = Date.now();
13732
14183
  await applicationStore?.save(state);
@@ -13754,7 +14205,8 @@ function createApplicationPipeline(config) {
13754
14205
  throw new Error(`Application ${applicationId} not found`);
13755
14206
  }
13756
14207
  const currentBatchFieldIds = state.batches?.[state.currentBatchIndex] ?? [];
13757
- const currentBatchFields = state.fields.filter(
14208
+ const activeFields = getActiveApplicationFields(state);
14209
+ const currentBatchFields = activeFields.filter(
13758
14210
  (f) => currentBatchFieldIds.includes(f.id)
13759
14211
  );
13760
14212
  onProgress?.("Classifying reply...");
@@ -13877,14 +14329,16 @@ Provide a brief, helpful explanation (2-3 sentences). End with "Just reply with
13877
14329
  responseText = `I wasn't able to generate an explanation for your question. Could you rephrase it, or just provide the answer directly?`;
13878
14330
  }
13879
14331
  }
13880
- const currentBatchComplete = currentBatchFieldIds.every(
14332
+ const activeCurrentBatchFieldIds = currentBatchFields.map((field) => field.id);
14333
+ const currentBatchComplete = activeCurrentBatchFieldIds.every(
13881
14334
  (fid) => state.fields.find((f) => f.id === fid)?.value
13882
14335
  );
13883
14336
  let nextBatchIndex;
13884
14337
  let nextBatchFields;
13885
14338
  if (state.batches) {
13886
14339
  for (let index = state.currentBatchIndex + 1; index < state.batches.length; index++) {
13887
- const candidateFields = state.fields.filter((f) => state.batches[index].includes(f.id));
14340
+ const activeCandidateFields = getActiveApplicationFields(state);
14341
+ const candidateFields = activeCandidateFields.filter((f) => state.batches[index].includes(f.id));
13888
14342
  if (candidateFields.some((f) => !f.value)) {
13889
14343
  nextBatchIndex = index;
13890
14344
  nextBatchFields = candidateFields;
@@ -13940,7 +14394,8 @@ ${emailText}`;
13940
14394
  }
13941
14395
  }
13942
14396
  state.updatedAt = Date.now();
13943
- state.qualityReport = state.qualityReport ?? buildApplicationQualityReport(state);
14397
+ state.contextProposals = proposeContextWrites(state);
14398
+ state.qualityReport = buildApplicationQualityReport(state);
13944
14399
  await applicationStore?.save(state);
13945
14400
  if (shouldFailQualityGate(qualityGate, state.qualityReport.qualityGateStatus)) {
13946
14401
  throw new Error("Application quality gate failed. See state.qualityReport for blocking issues.");
@@ -13960,7 +14415,7 @@ ${emailText}`;
13960
14415
  if (!state) throw new Error(`Application ${applicationId} not found`);
13961
14416
  if (!state.batches?.length) throw new Error("No batches available");
13962
14417
  const batchFieldIds = state.batches[state.currentBatchIndex];
13963
- const batchFields = state.fields.filter((f) => batchFieldIds.includes(f.id));
14418
+ const batchFields = getActiveApplicationFields(state).filter((f) => batchFieldIds.includes(f.id));
13964
14419
  const filledCount = state.fields.filter((f) => f.value).length;
13965
14420
  const { text, usage } = await generateBatchEmail(
13966
14421
  batchFields,
@@ -14008,13 +14463,86 @@ ${fieldSummary}`,
14008
14463
  trackUsage(usage);
14009
14464
  return { text, tokenUsage: totalUsage };
14010
14465
  }
14466
+ async function createApplicationRun2(input) {
14467
+ const state = createApplicationRun(input);
14468
+ await applicationStore?.save(state);
14469
+ return state;
14470
+ }
14471
+ async function planNextQuestions(applicationId, limit2) {
14472
+ const state = await applicationStore?.get(applicationId);
14473
+ if (!state) throw new Error(`Application ${applicationId} not found`);
14474
+ return planNextApplicationQuestions(state, limit2);
14475
+ }
14476
+ async function proposeContextWrites2(applicationId) {
14477
+ const state = await applicationStore?.get(applicationId);
14478
+ if (!state) throw new Error(`Application ${applicationId} not found`);
14479
+ const proposals = proposeContextWrites(state);
14480
+ await applicationStore?.save({
14481
+ ...state,
14482
+ contextProposals: proposals,
14483
+ updatedAt: Date.now()
14484
+ });
14485
+ return { proposals };
14486
+ }
14487
+ async function buildApplicationPacket2(input) {
14488
+ const state = await applicationStore?.get(input.applicationId);
14489
+ if (!state) throw new Error(`Application ${input.applicationId} not found`);
14490
+ const packet = buildApplicationPacket(state, {
14491
+ submissionNotes: input.submissionNotes,
14492
+ now: input.now
14493
+ });
14494
+ const reviewReport = validateApplicationPacket(packet);
14495
+ await applicationStore?.save({
14496
+ ...state,
14497
+ packet: { ...packet, qualityReport: reviewReport },
14498
+ status: reviewReport.qualityGateStatus === "failed" ? "broker_review" : "packet_ready",
14499
+ qualityReport: reviewReport,
14500
+ updatedAt: Date.now()
14501
+ });
14502
+ return { packet: { ...packet, qualityReport: reviewReport }, reviewReport };
14503
+ }
14011
14504
  return {
14012
14505
  processApplication,
14013
14506
  processReply: processReply2,
14014
14507
  generateCurrentBatchEmail,
14015
- getConfirmationSummary
14508
+ getConfirmationSummary,
14509
+ createApplicationRun: createApplicationRun2,
14510
+ planNextQuestions,
14511
+ proposeContextWrites: proposeContextWrites2,
14512
+ buildApplicationPacket: buildApplicationPacket2
14016
14513
  };
14017
14514
  }
14515
+ function selectMemoryBackfillMatch(field, chunks) {
14516
+ for (const chunk of chunks) {
14517
+ const value = chunk.metadata.value ?? chunk.metadata.answer ?? chunk.metadata.fieldValue;
14518
+ if (!value) continue;
14519
+ const metadataFieldId = chunk.metadata.fieldId ?? chunk.metadata.applicationFieldId;
14520
+ const metadataLabel = chunk.metadata.fieldLabel?.toLowerCase();
14521
+ const labelMatches = metadataLabel === field.label.toLowerCase();
14522
+ if (metadataFieldId && metadataFieldId !== field.id && !labelMatches) continue;
14523
+ return {
14524
+ value,
14525
+ source: chunk.metadata.source ?? `memory: ${chunk.documentId}`,
14526
+ confidence: metadataFieldId === field.id || labelMatches ? "high" : "medium",
14527
+ sourceSpanIds: parseSourceSpanIds(chunk.metadata.sourceSpanIds)
14528
+ };
14529
+ }
14530
+ return null;
14531
+ }
14532
+ function parseSourceSpanIds(value) {
14533
+ if (!value) return [];
14534
+ const trimmed = value.trim();
14535
+ if (!trimmed) return [];
14536
+ if (trimmed.startsWith("[")) {
14537
+ try {
14538
+ const parsed = JSON.parse(trimmed);
14539
+ return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string") : [];
14540
+ } catch {
14541
+ return [];
14542
+ }
14543
+ }
14544
+ return trimmed.split(",").map((item) => item.trim()).filter(Boolean);
14545
+ }
14018
14546
 
14019
14547
  // src/prompts/application/confirmation.ts
14020
14548
  function buildConfirmationSummaryPrompt(fields, applicationTitle) {
@@ -16094,13 +16622,21 @@ export {
16094
16622
  AgenticExecutionModeSchema,
16095
16623
  AnswerParsingResultSchema,
16096
16624
  ApplicationClassifyResultSchema,
16625
+ ApplicationContextProposalSchema,
16097
16626
  ApplicationEmailReviewSchema,
16098
16627
  ApplicationFieldSchema,
16628
+ ApplicationPacketAnswerSchema,
16629
+ ApplicationPacketSchema,
16099
16630
  ApplicationQualityArtifactSchema,
16100
16631
  ApplicationQualityIssueSchema,
16101
16632
  ApplicationQualityReportSchema,
16102
16633
  ApplicationQualityRoundSchema,
16634
+ ApplicationQuestionConditionSchema,
16635
+ ApplicationQuestionGraphSchema,
16636
+ ApplicationQuestionNodeSchema,
16637
+ ApplicationRepeatSchema,
16103
16638
  ApplicationStateSchema,
16639
+ ApplicationTemplateSchema,
16104
16640
  AttachmentInterpretationSchema,
16105
16641
  AuditTypeSchema,
16106
16642
  AutoFillMatchSchema,
@@ -16315,9 +16851,11 @@ export {
16315
16851
  VerifyResultSchema,
16316
16852
  WatercraftDeclarationsSchema,
16317
16853
  WorkersCompDeclarationsSchema,
16854
+ applyApplicationAnswers,
16318
16855
  buildAcroFormMappingPrompt,
16319
16856
  buildAgentSystemPrompt,
16320
16857
  buildAnswerParsingPrompt,
16858
+ buildApplicationPacket,
16321
16859
  buildAutoFillPrompt,
16322
16860
  buildBatchEmailGenerationPrompt,
16323
16861
  buildClassifyMessagePrompt,
@@ -16344,6 +16882,7 @@ export {
16344
16882
  buildPdfProviderOptions,
16345
16883
  buildQueryClassifyPrompt,
16346
16884
  buildQuestionBatchPrompt,
16885
+ buildQuestionGraphFromFields,
16347
16886
  buildQuotesPoliciesPrompt,
16348
16887
  buildReasonPrompt,
16349
16888
  buildReplyIntentClassificationPrompt,
@@ -16359,6 +16898,7 @@ export {
16359
16898
  collectPceEvidenceSources,
16360
16899
  compareSourceEvidence,
16361
16900
  createApplicationPipeline,
16901
+ createApplicationRun,
16362
16902
  createExtractor,
16363
16903
  createPceAgent,
16364
16904
  createPipelineContext,
@@ -16366,12 +16906,16 @@ export {
16366
16906
  evaluateCaseProposals,
16367
16907
  evidenceContainsQuote,
16368
16908
  extractPageRange,
16909
+ extractQuestionGraphFromFields,
16369
16910
  fillAcroForm,
16911
+ flattenQuestionGraph,
16370
16912
  generateNextMessage,
16371
16913
  getAcroFormFields,
16914
+ getActiveApplicationFields,
16372
16915
  getDoclingPageRangeText,
16373
16916
  getExtractor,
16374
16917
  getFileIdentifier,
16918
+ getNextApplicationQuestions,
16375
16919
  getPdfPageCount,
16376
16920
  getTemplate,
16377
16921
  isDoclingExtractionInput,
@@ -16379,6 +16923,7 @@ export {
16379
16923
  mergeOperationalProfile,
16380
16924
  mergeQuestionAnswers,
16381
16925
  mergeSourceSpans,
16926
+ normalizeApplicationQuestionGraph,
16382
16927
  normalizeDoclingDocument,
16383
16928
  normalizeDocumentSourceTreePaths,
16384
16929
  normalizeForMatch,
@@ -16388,7 +16933,9 @@ export {
16388
16933
  pLimit,
16389
16934
  pdfInputToBase64,
16390
16935
  pdfInputToBytes,
16936
+ planNextApplicationQuestions,
16391
16937
  processReply,
16938
+ proposeContextWrites,
16392
16939
  resolveModelBudget,
16393
16940
  safeGenerateObject,
16394
16941
  sanitizeNulls,
@@ -16401,6 +16948,7 @@ export {
16401
16948
  stableStringify,
16402
16949
  stripFences,
16403
16950
  toStrictSchema,
16951
+ validateApplicationPacket,
16404
16952
  validateEvidence,
16405
16953
  validatePceItems,
16406
16954
  validateQuotedEvidence,