@claritylabs/cl-sdk 0.11.0 → 0.13.0

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
@@ -36,9 +36,11 @@ __export(index_exports, {
36
36
  ApplicationQualityReportSchema: () => ApplicationQualityReportSchema,
37
37
  ApplicationQualityRoundSchema: () => ApplicationQualityRoundSchema,
38
38
  ApplicationStateSchema: () => ApplicationStateSchema,
39
+ AttachmentInterpretationSchema: () => AttachmentInterpretationSchema,
39
40
  AuditTypeSchema: () => AuditTypeSchema,
40
41
  AutoFillMatchSchema: () => AutoFillMatchSchema,
41
42
  AutoFillResultSchema: () => AutoFillResultSchema,
43
+ AuxiliaryFactSchema: () => AuxiliaryFactSchema,
42
44
  BOAT_TYPES: () => BOAT_TYPES,
43
45
  BindingAuthoritySchema: () => BindingAuthoritySchema,
44
46
  BoatTypeSchema: () => BoatTypeSchema,
@@ -157,6 +159,8 @@ __export(index_exports, {
157
159
  ProducerInfoSchema: () => ProducerInfoSchema,
158
160
  ProfessionalLiabilityDeclarationsSchema: () => ProfessionalLiabilityDeclarationsSchema,
159
161
  QUOTE_SECTION_TYPES: () => QUOTE_SECTION_TYPES,
162
+ QueryAttachmentKindSchema: () => QueryAttachmentKindSchema,
163
+ QueryAttachmentSchema: () => QueryAttachmentSchema,
160
164
  QueryClassifyResultSchema: () => QueryClassifyResultSchema,
161
165
  QueryIntentSchema: () => QueryIntentSchema,
162
166
  QueryResultSchema: () => QueryResultSchema,
@@ -215,6 +219,7 @@ __export(index_exports, {
215
219
  buildFormattingPrompt: () => buildFormattingPrompt,
216
220
  buildIdentityPrompt: () => buildIdentityPrompt,
217
221
  buildIntentPrompt: () => buildIntentPrompt,
222
+ buildInterpretAttachmentPrompt: () => buildInterpretAttachmentPrompt,
218
223
  buildLookupFillPrompt: () => buildLookupFillPrompt,
219
224
  buildQueryClassifyPrompt: () => buildQueryClassifyPrompt,
220
225
  buildQuestionBatchPrompt: () => buildQuestionBatchPrompt,
@@ -1467,6 +1472,12 @@ var PremiumLineSchema = import_zod16.z.object({
1467
1472
  line: import_zod16.z.string(),
1468
1473
  amount: import_zod16.z.string()
1469
1474
  });
1475
+ var AuxiliaryFactSchema = import_zod16.z.object({
1476
+ key: import_zod16.z.string(),
1477
+ value: import_zod16.z.string(),
1478
+ subject: import_zod16.z.string().optional(),
1479
+ context: import_zod16.z.string().optional()
1480
+ });
1470
1481
  var BaseDocumentFields = {
1471
1482
  id: import_zod16.z.string(),
1472
1483
  carrier: import_zod16.z.string(),
@@ -1532,7 +1543,8 @@ var BaseDocumentFields = {
1532
1543
  individualClaims: import_zod16.z.array(ClaimRecordSchema).optional(),
1533
1544
  experienceMod: ExperienceModSchema.optional(),
1534
1545
  cancellationNoticeDays: import_zod16.z.number().optional(),
1535
- nonrenewalNoticeDays: import_zod16.z.number().optional()
1546
+ nonrenewalNoticeDays: import_zod16.z.number().optional(),
1547
+ supplementaryFacts: import_zod16.z.array(AuxiliaryFactSchema).optional()
1536
1548
  };
1537
1549
  var PolicyDocumentSchema = import_zod16.z.object({
1538
1550
  ...BaseDocumentFields,
@@ -2195,6 +2207,7 @@ function assembleDocument(documentId, documentType, memory) {
2195
2207
  ...sanitizeNulls(coverages ?? {}),
2196
2208
  ...sanitizeNulls(premium ?? {}),
2197
2209
  ...sanitizeNulls(supplementary ?? {}),
2210
+ supplementaryFacts: supplementary?.auxiliaryFacts,
2198
2211
  endorsements: endorsements?.endorsements,
2199
2212
  exclusions: exclusions?.exclusions,
2200
2213
  conditions: conditions?.conditions,
@@ -2547,6 +2560,43 @@ Total Cost: ${doc.totalCost}` : ""}`,
2547
2560
  metadata: stringMetadata({ premium: doc.premium, documentType: doc.type })
2548
2561
  });
2549
2562
  }
2563
+ const supplementaryLines = [
2564
+ ...doc.claimsContacts?.map((contact) => `Claims Contact: ${[
2565
+ contact.name,
2566
+ contact.phone,
2567
+ contact.email,
2568
+ contact.hours
2569
+ ].filter(Boolean).join(" | ")}`) ?? [],
2570
+ ...doc.regulatoryContacts?.map((contact) => `Regulatory Contact: ${[
2571
+ contact.name,
2572
+ contact.phone,
2573
+ contact.email
2574
+ ].filter(Boolean).join(" | ")}`) ?? [],
2575
+ ...doc.thirdPartyAdministrators?.map((contact) => `TPA: ${[
2576
+ contact.name,
2577
+ contact.phone,
2578
+ contact.email
2579
+ ].filter(Boolean).join(" | ")}`) ?? [],
2580
+ ...doc.supplementaryFacts?.map((fact) => [
2581
+ fact.subject ? `Subject: ${fact.subject}` : null,
2582
+ `${fact.key}: ${fact.value}`,
2583
+ fact.context ? `Context: ${fact.context}` : null
2584
+ ].filter(Boolean).join(" | ")) ?? [],
2585
+ doc.cancellationNoticeDays != null ? `Cancellation Notice Days: ${doc.cancellationNoticeDays}` : null,
2586
+ doc.nonrenewalNoticeDays != null ? `Nonrenewal Notice Days: ${doc.nonrenewalNoticeDays}` : null
2587
+ ].filter((line) => Boolean(line));
2588
+ if (supplementaryLines.length > 0) {
2589
+ chunks.push({
2590
+ id: `${docId}:supplementary:0`,
2591
+ documentId: docId,
2592
+ type: "supplementary",
2593
+ text: supplementaryLines.join("\n"),
2594
+ metadata: stringMetadata({
2595
+ documentType: doc.type,
2596
+ supplementaryFactCount: doc.supplementaryFacts?.length
2597
+ })
2598
+ });
2599
+ }
2550
2600
  return chunks;
2551
2601
  }
2552
2602
 
@@ -2630,6 +2680,32 @@ function mergeArrayPayload(existing, incoming, arrayKey, keyFn) {
2630
2680
  merged[arrayKey] = mergeUniqueObjects(existingItems, incomingItems, keyFn);
2631
2681
  return merged;
2632
2682
  }
2683
+ function mergeSupplementary(existing, incoming) {
2684
+ const merged = mergeShallowPreferPresent(existing, incoming);
2685
+ const mergeContactArray = (arrayKey) => {
2686
+ const existingItems = Array.isArray(existing[arrayKey]) ? existing[arrayKey] : [];
2687
+ const incomingItems = Array.isArray(incoming[arrayKey]) ? incoming[arrayKey] : [];
2688
+ merged[arrayKey] = mergeUniqueObjects(existingItems, incomingItems, (item) => [
2689
+ String(item.name ?? "").toLowerCase(),
2690
+ String(item.phone ?? "").toLowerCase(),
2691
+ String(item.email ?? "").toLowerCase(),
2692
+ String(item.address ?? "").toLowerCase(),
2693
+ String(item.type ?? "").toLowerCase()
2694
+ ].join("|"));
2695
+ };
2696
+ mergeContactArray("regulatoryContacts");
2697
+ mergeContactArray("claimsContacts");
2698
+ mergeContactArray("thirdPartyAdministrators");
2699
+ const existingFacts = Array.isArray(existing.auxiliaryFacts) ? existing.auxiliaryFacts : [];
2700
+ const incomingFacts = Array.isArray(incoming.auxiliaryFacts) ? incoming.auxiliaryFacts : [];
2701
+ merged.auxiliaryFacts = mergeUniqueObjects(existingFacts, incomingFacts, (item) => [
2702
+ String(item.key ?? "").toLowerCase(),
2703
+ String(item.value ?? "").toLowerCase(),
2704
+ String(item.subject ?? "").toLowerCase(),
2705
+ String(item.context ?? "").toLowerCase()
2706
+ ].join("|"));
2707
+ return merged;
2708
+ }
2633
2709
  function mergeExtractorResult(extractorName, existing, incoming) {
2634
2710
  if (!existing) return incoming;
2635
2711
  if (!incoming) return existing;
@@ -2640,9 +2716,10 @@ function mergeExtractorResult(extractorName, existing, incoming) {
2640
2716
  case "carrier_info":
2641
2717
  case "named_insured":
2642
2718
  case "loss_history":
2643
- case "supplementary":
2644
2719
  case "premium_breakdown":
2645
2720
  return mergeShallowPreferPresent(current, next);
2721
+ case "supplementary":
2722
+ return mergeSupplementary(current, next);
2646
2723
  case "coverage_limits":
2647
2724
  return mergeCoverageLimits(current, next);
2648
2725
  case "declarations":
@@ -4239,15 +4316,22 @@ var ContactSchema2 = import_zod33.z.object({
4239
4316
  address: import_zod33.z.string().optional().describe("Mailing address"),
4240
4317
  type: import_zod33.z.string().optional().describe("Contact type, e.g. 'State Department of Insurance'")
4241
4318
  });
4319
+ var AuxiliaryFactSchema2 = import_zod33.z.object({
4320
+ key: import_zod33.z.string().describe("Normalized machine-readable fact key, e.g. 'policyholder_age' or 'insured_name'"),
4321
+ value: import_zod33.z.string().describe("Concrete extracted fact value"),
4322
+ subject: import_zod33.z.string().optional().describe("Person, entity, vehicle, property, or schedule item this fact belongs to"),
4323
+ context: import_zod33.z.string().optional().describe("Short disambiguating context, such as 'Driver Schedule' or 'Named Insured'")
4324
+ });
4242
4325
  var SupplementarySchema = import_zod33.z.object({
4243
4326
  regulatoryContacts: import_zod33.z.array(ContactSchema2).optional().describe("Regulatory body contacts (state department of insurance, ombudsman)"),
4244
4327
  claimsContacts: import_zod33.z.array(ContactSchema2).optional().describe("Claims reporting contacts and instructions"),
4245
4328
  thirdPartyAdministrators: import_zod33.z.array(ContactSchema2).optional().describe("Third-party administrators for claims handling"),
4246
4329
  cancellationNoticeDays: import_zod33.z.number().optional().describe("Required notice period for cancellation in days"),
4247
- nonrenewalNoticeDays: import_zod33.z.number().optional().describe("Required notice period for nonrenewal in days")
4330
+ nonrenewalNoticeDays: import_zod33.z.number().optional().describe("Required notice period for nonrenewal in days"),
4331
+ auxiliaryFacts: import_zod33.z.array(AuxiliaryFactSchema2).optional().describe("Additional retrieval-only facts that do not fit the strict primary schema")
4248
4332
  });
4249
4333
  function buildSupplementaryPrompt() {
4250
- return `You are an expert insurance document analyst. Extract supplementary and regulatory information from this document.
4334
+ return `You are an expert insurance document analyst. Extract supplementary, retrieval-only information from this document.
4251
4335
 
4252
4336
  Focus on:
4253
4337
  - Regulatory contacts: state department of insurance, regulatory bodies, ombudsman offices \u2014 with phone, email, address
@@ -4257,9 +4341,19 @@ Focus on:
4257
4341
  - Nonrenewal notice period in days
4258
4342
  - Complaint filing procedures and contacts
4259
4343
  - Governing law or jurisdiction provisions
4344
+ - Additional policy-specific facts that are useful for memory and retrieval even if they do not belong in the strict primary schema
4260
4345
 
4261
4346
  Look for regulatory notices, complaint contact sections, claims reporting instructions, and cancellation/nonrenewal provisions throughout the document.
4262
4347
 
4348
+ For auxiliaryFacts:
4349
+ - Capture concrete, policy-specific facts as structured key/value pairs.
4350
+ - Prioritize facts that agents may need later but that are often omitted from strict schemas: policyholder names, insured person names, driver names, ages, dates of birth, marital status, garaging information, lienholders, household members, vehicle assignments, schedule row details, and other discrete identifiers.
4351
+ - Use short normalized keys like "policyholder_name", "policyholder_age", "insured_name", "driver_age", "driver_date_of_birth", "garaging_zip", "vehicle_principal_driver".
4352
+ - Use subject when the fact belongs to a specific person, vehicle, property, or scheduled item.
4353
+ - Do not invent facts.
4354
+ - Do not include vague boilerplate or generic form language.
4355
+ - Do not repeat large narrative excerpts; keep facts atomic.
4356
+
4263
4357
  Return JSON only.`;
4264
4358
  }
4265
4359
 
@@ -4986,6 +5080,28 @@ function createExtractor(config) {
4986
5080
  mergeMemoryResult(result.name, result.data, memory);
4987
5081
  }
4988
5082
  }
5083
+ const supplementaryExtractor = getExtractor("supplementary");
5084
+ if (supplementaryExtractor) {
5085
+ onProgress?.("Extracting supplementary retrieval facts...");
5086
+ try {
5087
+ const supplementaryResult = await runExtractor({
5088
+ name: "supplementary",
5089
+ prompt: supplementaryExtractor.buildPrompt(),
5090
+ schema: supplementaryExtractor.schema,
5091
+ pdfBase64,
5092
+ startPage: 1,
5093
+ endPage: pageCount,
5094
+ generateObject,
5095
+ convertPdfToImages,
5096
+ maxTokens: supplementaryExtractor.maxTokens ?? 4096,
5097
+ providerOptions
5098
+ });
5099
+ trackUsage(supplementaryResult.usage);
5100
+ mergeMemoryResult(supplementaryResult.name, supplementaryResult.data, memory);
5101
+ } catch (error) {
5102
+ await log?.(`Supplementary extractor failed: ${error}`);
5103
+ }
5104
+ }
4989
5105
  await pipelineCtx.save("extract", {
4990
5106
  id,
4991
5107
  pageCount,
@@ -6575,7 +6691,7 @@ Respond with the explanation text only \u2014 no JSON, no field ID, no extra for
6575
6691
  }
6576
6692
 
6577
6693
  // src/prompts/query/classify.ts
6578
- function buildQueryClassifyPrompt(question, conversationContext) {
6694
+ function buildQueryClassifyPrompt(question, conversationContext, attachmentContext) {
6579
6695
  return `You are a query classifier for an insurance document intelligence system.
6580
6696
 
6581
6697
  Analyze the user's question and produce a structured classification.
@@ -6585,6 +6701,9 @@ ${question}
6585
6701
  ${conversationContext ? `
6586
6702
  CONVERSATION CONTEXT:
6587
6703
  ${conversationContext}` : ""}
6704
+ ${attachmentContext ? `
6705
+ ATTACHMENT CONTEXT:
6706
+ ${attachmentContext}` : ""}
6588
6707
 
6589
6708
  INSTRUCTIONS:
6590
6709
 
@@ -6605,6 +6724,7 @@ INSTRUCTIONS:
6605
6724
  - requiresDocumentLookup: true if a specific document needs to be fetched by ID/number/carrier
6606
6725
  - requiresChunkSearch: true if semantic search over document chunks is needed
6607
6726
  - requiresConversationHistory: true if the question references prior conversation
6727
+ - If the user's attachment already contains critical facts, still request chunk/document lookup when policy or quote details should be cross-checked against stored records
6608
6728
 
6609
6729
  CHUNK TYPES (for chunkTypes filter):
6610
6730
  carrier_info, named_insured, coverage, endorsement, exclusion, condition, section, declaration, loss_history, premium, supplementary
@@ -6646,6 +6766,16 @@ var QueryIntentSchema = import_zod35.z.enum([
6646
6766
  "claims_inquiry",
6647
6767
  "general_knowledge"
6648
6768
  ]);
6769
+ var QueryAttachmentKindSchema = import_zod35.z.enum(["image", "pdf", "text"]);
6770
+ var QueryAttachmentSchema = import_zod35.z.object({
6771
+ id: import_zod35.z.string().optional().describe("Optional stable attachment ID from the caller"),
6772
+ kind: QueryAttachmentKindSchema,
6773
+ name: import_zod35.z.string().optional().describe("Original filename or user-facing label"),
6774
+ mimeType: import_zod35.z.string().optional().describe("MIME type such as image/jpeg or application/pdf"),
6775
+ base64: import_zod35.z.string().optional().describe("Base64-encoded file content for image/pdf attachments"),
6776
+ text: import_zod35.z.string().optional().describe("Plain-text attachment content when available"),
6777
+ description: import_zod35.z.string().optional().describe("Caller-provided description of the attachment")
6778
+ });
6649
6779
  var SubQuestionSchema = import_zod35.z.object({
6650
6780
  question: import_zod35.z.string().describe("Atomic sub-question to retrieve and answer independently"),
6651
6781
  intent: QueryIntentSchema,
@@ -6666,14 +6796,21 @@ var QueryClassifyResultSchema = import_zod35.z.object({
6666
6796
  requiresConversationHistory: import_zod35.z.boolean().describe("Whether conversation history is relevant")
6667
6797
  });
6668
6798
  var EvidenceItemSchema = import_zod35.z.object({
6669
- source: import_zod35.z.enum(["chunk", "document", "conversation"]),
6799
+ source: import_zod35.z.enum(["chunk", "document", "conversation", "attachment"]),
6670
6800
  chunkId: import_zod35.z.string().optional(),
6671
6801
  documentId: import_zod35.z.string().optional(),
6672
6802
  turnId: import_zod35.z.string().optional(),
6803
+ attachmentId: import_zod35.z.string().optional(),
6673
6804
  text: import_zod35.z.string().describe("Text excerpt from the source"),
6674
6805
  relevance: import_zod35.z.number().min(0).max(1),
6675
6806
  metadata: import_zod35.z.array(import_zod35.z.object({ key: import_zod35.z.string(), value: import_zod35.z.string() })).optional()
6676
6807
  });
6808
+ var AttachmentInterpretationSchema = import_zod35.z.object({
6809
+ summary: import_zod35.z.string().describe("Concise summary of what the attachment shows or contains"),
6810
+ extractedFacts: import_zod35.z.array(import_zod35.z.string()).describe("Specific observable or document facts grounded in the attachment"),
6811
+ recommendedFocus: import_zod35.z.array(import_zod35.z.string()).describe("Important details to incorporate when answering follow-up questions"),
6812
+ confidence: import_zod35.z.number().min(0).max(1)
6813
+ });
6677
6814
  var RetrievalResultSchema = import_zod35.z.object({
6678
6815
  subQuestion: import_zod35.z.string(),
6679
6816
  evidence: import_zod35.z.array(EvidenceItemSchema)
@@ -6994,7 +7131,7 @@ async function verify(originalQuestion, subAnswers, allEvidence, config) {
6994
7131
 
6995
7132
  // src/query/quality.ts
6996
7133
  function sourceIdForEvidence(evidence) {
6997
- return evidence.chunkId ?? evidence.documentId ?? evidence.turnId;
7134
+ return evidence.chunkId ?? evidence.documentId ?? evidence.turnId ?? evidence.attachmentId;
6998
7135
  }
6999
7136
  function citationSourceId(citation) {
7000
7137
  return citation.chunkId || citation.documentId;
@@ -7098,6 +7235,152 @@ function buildQueryReviewReport(params) {
7098
7235
  };
7099
7236
  }
7100
7237
 
7238
+ // src/prompts/query/interpret-attachment.ts
7239
+ function buildInterpretAttachmentPrompt(question, attachment) {
7240
+ const attachmentLabel = attachment.name ?? attachment.id ?? "attachment";
7241
+ const descriptor = [
7242
+ `Attachment: ${attachmentLabel}`,
7243
+ `Kind: ${attachment.kind}`,
7244
+ attachment.mimeType ? `MIME type: ${attachment.mimeType}` : null,
7245
+ attachment.description ? `Caller description: ${attachment.description}` : null
7246
+ ].filter(Boolean).join("\n");
7247
+ return `You are interpreting a user-supplied attachment for an insurance-support question.
7248
+
7249
+ USER QUESTION:
7250
+ ${question}
7251
+
7252
+ ATTACHMENT METADATA:
7253
+ ${descriptor}
7254
+
7255
+ ${attachment.kind === "text" && attachment.text ? `ATTACHMENT TEXT:
7256
+ ${attachment.text}
7257
+ ` : "The attachment content is provided separately as a file or image input.\n"}
7258
+ INSTRUCTIONS:
7259
+ 1. Describe what the attachment appears to show or contain in a concise summary.
7260
+ 2. Extract concrete facts that may matter when answering the user's question.
7261
+ 3. Note the most important details to carry forward into follow-up questions.
7262
+ 4. If the attachment is a document, identify the key business or insurance details visible.
7263
+ 5. If the attachment is a photo of damage or a real-world issue, describe the observable issue without guessing beyond what is visible.
7264
+ 6. Do not invent unreadable text. If something is unclear, say so in the summary or extracted facts.
7265
+
7266
+ Respond with the structured interpretation.`;
7267
+ }
7268
+
7269
+ // src/query/multimodal.ts
7270
+ function attachmentSourceId(attachment, index) {
7271
+ return attachment.id ?? `attachment-${index + 1}`;
7272
+ }
7273
+ function buildAttachmentProviderOptions(attachment, providerOptions) {
7274
+ const merged = {
7275
+ ...providerOptions,
7276
+ attachments: [
7277
+ {
7278
+ kind: attachment.kind,
7279
+ name: attachment.name,
7280
+ mimeType: attachment.mimeType,
7281
+ base64: attachment.base64,
7282
+ text: attachment.text,
7283
+ description: attachment.description
7284
+ }
7285
+ ]
7286
+ };
7287
+ if (attachment.kind === "pdf" && attachment.base64) {
7288
+ merged.pdfBase64 = attachment.base64;
7289
+ }
7290
+ if (attachment.kind === "image" && attachment.base64) {
7291
+ merged.images = [
7292
+ {
7293
+ imageBase64: attachment.base64,
7294
+ mimeType: attachment.mimeType ?? "image/jpeg"
7295
+ }
7296
+ ];
7297
+ }
7298
+ return merged;
7299
+ }
7300
+ function buildAttachmentEvidenceText(attachment, interpretation) {
7301
+ const lines = [
7302
+ `Attachment kind: ${attachment.kind}`,
7303
+ attachment.name ? `Attachment name: ${attachment.name}` : null,
7304
+ attachment.mimeType ? `MIME type: ${attachment.mimeType}` : null,
7305
+ attachment.description ? `Caller description: ${attachment.description}` : null,
7306
+ `Summary: ${interpretation.summary}`,
7307
+ interpretation.extractedFacts.length > 0 ? `Extracted facts:
7308
+ ${interpretation.extractedFacts.map((fact) => `- ${fact}`).join("\n")}` : null,
7309
+ interpretation.recommendedFocus.length > 0 ? `Important follow-up details:
7310
+ ${interpretation.recommendedFocus.map((item) => `- ${item}`).join("\n")}` : null,
7311
+ attachment.kind === "text" && attachment.text ? `Original text:
7312
+ ${attachment.text}` : null
7313
+ ];
7314
+ return lines.filter(Boolean).join("\n");
7315
+ }
7316
+ async function interpretAttachments(params) {
7317
+ const { attachments = [], question, generateObject, providerOptions, log, onUsage } = params;
7318
+ if (attachments.length === 0) {
7319
+ return { evidence: [] };
7320
+ }
7321
+ const evidence = [];
7322
+ for (const [index, attachment] of attachments.entries()) {
7323
+ const id = attachmentSourceId(attachment, index);
7324
+ if (attachment.kind === "text" && attachment.text) {
7325
+ const textEvidence = buildAttachmentEvidenceText(attachment, {
7326
+ summary: attachment.description ?? "User supplied text context.",
7327
+ extractedFacts: [attachment.text],
7328
+ recommendedFocus: [],
7329
+ confidence: 1
7330
+ });
7331
+ evidence.push({
7332
+ source: "attachment",
7333
+ attachmentId: id,
7334
+ chunkId: id,
7335
+ documentId: id,
7336
+ text: textEvidence,
7337
+ relevance: 0.95,
7338
+ metadata: [
7339
+ { key: "kind", value: attachment.kind },
7340
+ ...attachment.name ? [{ key: "name", value: attachment.name }] : []
7341
+ ]
7342
+ });
7343
+ continue;
7344
+ }
7345
+ const prompt = buildInterpretAttachmentPrompt(question, attachment);
7346
+ const { object, usage } = await safeGenerateObject(
7347
+ generateObject,
7348
+ {
7349
+ prompt,
7350
+ schema: AttachmentInterpretationSchema,
7351
+ maxTokens: 2048,
7352
+ providerOptions: buildAttachmentProviderOptions(attachment, providerOptions)
7353
+ },
7354
+ {
7355
+ fallback: {
7356
+ summary: attachment.description ?? `User supplied ${attachment.kind} attachment.`,
7357
+ extractedFacts: [],
7358
+ recommendedFocus: [],
7359
+ confidence: 0.2
7360
+ },
7361
+ log,
7362
+ onError: (error, attempt) => log?.(`Attachment interpretation attempt ${attempt + 1} failed for "${attachment.name ?? id}": ${error}`)
7363
+ }
7364
+ );
7365
+ onUsage?.(usage);
7366
+ evidence.push({
7367
+ source: "attachment",
7368
+ attachmentId: id,
7369
+ chunkId: id,
7370
+ documentId: id,
7371
+ text: buildAttachmentEvidenceText(attachment, object),
7372
+ relevance: Math.max(0.7, object.confidence),
7373
+ metadata: [
7374
+ { key: "kind", value: attachment.kind },
7375
+ ...attachment.name ? [{ key: "name", value: attachment.name }] : []
7376
+ ]
7377
+ });
7378
+ }
7379
+ const contextSummary = evidence.map((item, index) => `Attachment ${index + 1}:
7380
+ ${item.text}`).join("\n\n");
7381
+ return { evidence, contextSummary };
7382
+ }
7383
+
7101
7384
  // src/query/coordinator.ts
7102
7385
  function createQueryAgent(config) {
7103
7386
  const {
@@ -7125,13 +7408,23 @@ function createQueryAgent(config) {
7125
7408
  }
7126
7409
  async function query(input) {
7127
7410
  totalUsage = { inputTokens: 0, outputTokens: 0 };
7128
- const { question, conversationId, context } = input;
7411
+ const { question, conversationId, context, attachments } = input;
7129
7412
  const pipelineCtx = createPipelineContext({
7130
7413
  id: `query-${Date.now()}`
7131
7414
  });
7415
+ onProgress?.("Interpreting attachments...");
7416
+ const { evidence: attachmentEvidence, contextSummary: attachmentContext } = await interpretAttachments({
7417
+ attachments,
7418
+ question,
7419
+ generateObject,
7420
+ providerOptions,
7421
+ log,
7422
+ onUsage: trackUsage
7423
+ });
7424
+ await pipelineCtx.save("attachments", { attachmentEvidence });
7132
7425
  onProgress?.("Classifying query...");
7133
- const classification = await classify(question, conversationId);
7134
- await pipelineCtx.save("classify", { classification });
7426
+ const classification = await classify(question, conversationId, attachmentContext);
7427
+ await pipelineCtx.save("classify", { classification, attachmentEvidence });
7135
7428
  onProgress?.(`Retrieving evidence for ${classification.subQuestions.length} sub-question(s)...`);
7136
7429
  const retrieverConfig = {
7137
7430
  documentStore,
@@ -7144,8 +7437,8 @@ function createQueryAgent(config) {
7144
7437
  (sq) => limit(() => retrieve(sq, conversationId, retrieverConfig))
7145
7438
  )
7146
7439
  );
7147
- const allEvidence = retrievalResults.flatMap((r) => r.evidence);
7148
- await pipelineCtx.save("retrieve", { classification, evidence: allEvidence });
7440
+ const allEvidence = [...attachmentEvidence, ...retrievalResults.flatMap((r) => r.evidence)];
7441
+ await pipelineCtx.save("retrieve", { classification, attachmentEvidence, evidence: allEvidence });
7149
7442
  onProgress?.("Reasoning over evidence...");
7150
7443
  const reasonerConfig = { generateObject, providerOptions };
7151
7444
  const reasonResults = await Promise.allSettled(
@@ -7154,7 +7447,7 @@ function createQueryAgent(config) {
7154
7447
  const { subAnswer, usage } = await reason(
7155
7448
  sq.question,
7156
7449
  sq.intent,
7157
- retrievalResults[i].evidence,
7450
+ [...attachmentEvidence, ...retrievalResults[i].evidence],
7158
7451
  reasonerConfig
7159
7452
  );
7160
7453
  trackUsage(usage);
@@ -7178,7 +7471,7 @@ function createQueryAgent(config) {
7178
7471
  });
7179
7472
  }
7180
7473
  }
7181
- await pipelineCtx.save("reason", { classification, evidence: allEvidence, subAnswers });
7474
+ await pipelineCtx.save("reason", { classification, attachmentEvidence, evidence: allEvidence, subAnswers });
7182
7475
  onProgress?.("Verifying answer grounding...");
7183
7476
  const verifierConfig = { generateObject, providerOptions };
7184
7477
  const verifyRounds = [];
@@ -7226,7 +7519,7 @@ function createQueryAgent(config) {
7226
7519
  const { subAnswer, usage: u } = await reason(
7227
7520
  sq.question,
7228
7521
  sq.intent,
7229
- retryRetrievals[i].evidence,
7522
+ [...attachmentEvidence, ...retryRetrievals[i].evidence],
7230
7523
  reasonerConfig
7231
7524
  );
7232
7525
  trackUsage(u);
@@ -7261,6 +7554,7 @@ function createQueryAgent(config) {
7261
7554
  });
7262
7555
  await pipelineCtx.save("review", {
7263
7556
  classification,
7557
+ attachmentEvidence,
7264
7558
  evidence: allEvidence,
7265
7559
  subAnswers,
7266
7560
  reviewReport
@@ -7293,7 +7587,7 @@ function createQueryAgent(config) {
7293
7587
  }
7294
7588
  return { ...queryResult, tokenUsage: totalUsage, reviewReport };
7295
7589
  }
7296
- async function classify(question, conversationId) {
7590
+ async function classify(question, conversationId, attachmentContext) {
7297
7591
  let conversationContext;
7298
7592
  if (conversationId) {
7299
7593
  try {
@@ -7304,7 +7598,7 @@ function createQueryAgent(config) {
7304
7598
  } catch {
7305
7599
  }
7306
7600
  }
7307
- const prompt = buildQueryClassifyPrompt(question, conversationContext);
7601
+ const prompt = buildQueryClassifyPrompt(question, conversationContext, attachmentContext);
7308
7602
  const { object, usage } = await safeGenerateObject(
7309
7603
  generateObject,
7310
7604
  {
@@ -7520,9 +7814,11 @@ var AGENT_TOOLS = [
7520
7814
  ApplicationQualityReportSchema,
7521
7815
  ApplicationQualityRoundSchema,
7522
7816
  ApplicationStateSchema,
7817
+ AttachmentInterpretationSchema,
7523
7818
  AuditTypeSchema,
7524
7819
  AutoFillMatchSchema,
7525
7820
  AutoFillResultSchema,
7821
+ AuxiliaryFactSchema,
7526
7822
  BOAT_TYPES,
7527
7823
  BindingAuthoritySchema,
7528
7824
  BoatTypeSchema,
@@ -7641,6 +7937,8 @@ var AGENT_TOOLS = [
7641
7937
  ProducerInfoSchema,
7642
7938
  ProfessionalLiabilityDeclarationsSchema,
7643
7939
  QUOTE_SECTION_TYPES,
7940
+ QueryAttachmentKindSchema,
7941
+ QueryAttachmentSchema,
7644
7942
  QueryClassifyResultSchema,
7645
7943
  QueryIntentSchema,
7646
7944
  QueryResultSchema,
@@ -7699,6 +7997,7 @@ var AGENT_TOOLS = [
7699
7997
  buildFormattingPrompt,
7700
7998
  buildIdentityPrompt,
7701
7999
  buildIntentPrompt,
8000
+ buildInterpretAttachmentPrompt,
7702
8001
  buildLookupFillPrompt,
7703
8002
  buildQueryClassifyPrompt,
7704
8003
  buildQuestionBatchPrompt,