@claritylabs/cl-sdk 0.11.0 → 0.12.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,6 +36,7 @@ __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,
@@ -157,6 +158,8 @@ __export(index_exports, {
157
158
  ProducerInfoSchema: () => ProducerInfoSchema,
158
159
  ProfessionalLiabilityDeclarationsSchema: () => ProfessionalLiabilityDeclarationsSchema,
159
160
  QUOTE_SECTION_TYPES: () => QUOTE_SECTION_TYPES,
161
+ QueryAttachmentKindSchema: () => QueryAttachmentKindSchema,
162
+ QueryAttachmentSchema: () => QueryAttachmentSchema,
160
163
  QueryClassifyResultSchema: () => QueryClassifyResultSchema,
161
164
  QueryIntentSchema: () => QueryIntentSchema,
162
165
  QueryResultSchema: () => QueryResultSchema,
@@ -215,6 +218,7 @@ __export(index_exports, {
215
218
  buildFormattingPrompt: () => buildFormattingPrompt,
216
219
  buildIdentityPrompt: () => buildIdentityPrompt,
217
220
  buildIntentPrompt: () => buildIntentPrompt,
221
+ buildInterpretAttachmentPrompt: () => buildInterpretAttachmentPrompt,
218
222
  buildLookupFillPrompt: () => buildLookupFillPrompt,
219
223
  buildQueryClassifyPrompt: () => buildQueryClassifyPrompt,
220
224
  buildQuestionBatchPrompt: () => buildQuestionBatchPrompt,
@@ -6575,7 +6579,7 @@ Respond with the explanation text only \u2014 no JSON, no field ID, no extra for
6575
6579
  }
6576
6580
 
6577
6581
  // src/prompts/query/classify.ts
6578
- function buildQueryClassifyPrompt(question, conversationContext) {
6582
+ function buildQueryClassifyPrompt(question, conversationContext, attachmentContext) {
6579
6583
  return `You are a query classifier for an insurance document intelligence system.
6580
6584
 
6581
6585
  Analyze the user's question and produce a structured classification.
@@ -6585,6 +6589,9 @@ ${question}
6585
6589
  ${conversationContext ? `
6586
6590
  CONVERSATION CONTEXT:
6587
6591
  ${conversationContext}` : ""}
6592
+ ${attachmentContext ? `
6593
+ ATTACHMENT CONTEXT:
6594
+ ${attachmentContext}` : ""}
6588
6595
 
6589
6596
  INSTRUCTIONS:
6590
6597
 
@@ -6605,6 +6612,7 @@ INSTRUCTIONS:
6605
6612
  - requiresDocumentLookup: true if a specific document needs to be fetched by ID/number/carrier
6606
6613
  - requiresChunkSearch: true if semantic search over document chunks is needed
6607
6614
  - requiresConversationHistory: true if the question references prior conversation
6615
+ - 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
6616
 
6609
6617
  CHUNK TYPES (for chunkTypes filter):
6610
6618
  carrier_info, named_insured, coverage, endorsement, exclusion, condition, section, declaration, loss_history, premium, supplementary
@@ -6646,6 +6654,16 @@ var QueryIntentSchema = import_zod35.z.enum([
6646
6654
  "claims_inquiry",
6647
6655
  "general_knowledge"
6648
6656
  ]);
6657
+ var QueryAttachmentKindSchema = import_zod35.z.enum(["image", "pdf", "text"]);
6658
+ var QueryAttachmentSchema = import_zod35.z.object({
6659
+ id: import_zod35.z.string().optional().describe("Optional stable attachment ID from the caller"),
6660
+ kind: QueryAttachmentKindSchema,
6661
+ name: import_zod35.z.string().optional().describe("Original filename or user-facing label"),
6662
+ mimeType: import_zod35.z.string().optional().describe("MIME type such as image/jpeg or application/pdf"),
6663
+ base64: import_zod35.z.string().optional().describe("Base64-encoded file content for image/pdf attachments"),
6664
+ text: import_zod35.z.string().optional().describe("Plain-text attachment content when available"),
6665
+ description: import_zod35.z.string().optional().describe("Caller-provided description of the attachment")
6666
+ });
6649
6667
  var SubQuestionSchema = import_zod35.z.object({
6650
6668
  question: import_zod35.z.string().describe("Atomic sub-question to retrieve and answer independently"),
6651
6669
  intent: QueryIntentSchema,
@@ -6666,14 +6684,21 @@ var QueryClassifyResultSchema = import_zod35.z.object({
6666
6684
  requiresConversationHistory: import_zod35.z.boolean().describe("Whether conversation history is relevant")
6667
6685
  });
6668
6686
  var EvidenceItemSchema = import_zod35.z.object({
6669
- source: import_zod35.z.enum(["chunk", "document", "conversation"]),
6687
+ source: import_zod35.z.enum(["chunk", "document", "conversation", "attachment"]),
6670
6688
  chunkId: import_zod35.z.string().optional(),
6671
6689
  documentId: import_zod35.z.string().optional(),
6672
6690
  turnId: import_zod35.z.string().optional(),
6691
+ attachmentId: import_zod35.z.string().optional(),
6673
6692
  text: import_zod35.z.string().describe("Text excerpt from the source"),
6674
6693
  relevance: import_zod35.z.number().min(0).max(1),
6675
6694
  metadata: import_zod35.z.array(import_zod35.z.object({ key: import_zod35.z.string(), value: import_zod35.z.string() })).optional()
6676
6695
  });
6696
+ var AttachmentInterpretationSchema = import_zod35.z.object({
6697
+ summary: import_zod35.z.string().describe("Concise summary of what the attachment shows or contains"),
6698
+ extractedFacts: import_zod35.z.array(import_zod35.z.string()).describe("Specific observable or document facts grounded in the attachment"),
6699
+ recommendedFocus: import_zod35.z.array(import_zod35.z.string()).describe("Important details to incorporate when answering follow-up questions"),
6700
+ confidence: import_zod35.z.number().min(0).max(1)
6701
+ });
6677
6702
  var RetrievalResultSchema = import_zod35.z.object({
6678
6703
  subQuestion: import_zod35.z.string(),
6679
6704
  evidence: import_zod35.z.array(EvidenceItemSchema)
@@ -6994,7 +7019,7 @@ async function verify(originalQuestion, subAnswers, allEvidence, config) {
6994
7019
 
6995
7020
  // src/query/quality.ts
6996
7021
  function sourceIdForEvidence(evidence) {
6997
- return evidence.chunkId ?? evidence.documentId ?? evidence.turnId;
7022
+ return evidence.chunkId ?? evidence.documentId ?? evidence.turnId ?? evidence.attachmentId;
6998
7023
  }
6999
7024
  function citationSourceId(citation) {
7000
7025
  return citation.chunkId || citation.documentId;
@@ -7098,6 +7123,152 @@ function buildQueryReviewReport(params) {
7098
7123
  };
7099
7124
  }
7100
7125
 
7126
+ // src/prompts/query/interpret-attachment.ts
7127
+ function buildInterpretAttachmentPrompt(question, attachment) {
7128
+ const attachmentLabel = attachment.name ?? attachment.id ?? "attachment";
7129
+ const descriptor = [
7130
+ `Attachment: ${attachmentLabel}`,
7131
+ `Kind: ${attachment.kind}`,
7132
+ attachment.mimeType ? `MIME type: ${attachment.mimeType}` : null,
7133
+ attachment.description ? `Caller description: ${attachment.description}` : null
7134
+ ].filter(Boolean).join("\n");
7135
+ return `You are interpreting a user-supplied attachment for an insurance-support question.
7136
+
7137
+ USER QUESTION:
7138
+ ${question}
7139
+
7140
+ ATTACHMENT METADATA:
7141
+ ${descriptor}
7142
+
7143
+ ${attachment.kind === "text" && attachment.text ? `ATTACHMENT TEXT:
7144
+ ${attachment.text}
7145
+ ` : "The attachment content is provided separately as a file or image input.\n"}
7146
+ INSTRUCTIONS:
7147
+ 1. Describe what the attachment appears to show or contain in a concise summary.
7148
+ 2. Extract concrete facts that may matter when answering the user's question.
7149
+ 3. Note the most important details to carry forward into follow-up questions.
7150
+ 4. If the attachment is a document, identify the key business or insurance details visible.
7151
+ 5. If the attachment is a photo of damage or a real-world issue, describe the observable issue without guessing beyond what is visible.
7152
+ 6. Do not invent unreadable text. If something is unclear, say so in the summary or extracted facts.
7153
+
7154
+ Respond with the structured interpretation.`;
7155
+ }
7156
+
7157
+ // src/query/multimodal.ts
7158
+ function attachmentSourceId(attachment, index) {
7159
+ return attachment.id ?? `attachment-${index + 1}`;
7160
+ }
7161
+ function buildAttachmentProviderOptions(attachment, providerOptions) {
7162
+ const merged = {
7163
+ ...providerOptions,
7164
+ attachments: [
7165
+ {
7166
+ kind: attachment.kind,
7167
+ name: attachment.name,
7168
+ mimeType: attachment.mimeType,
7169
+ base64: attachment.base64,
7170
+ text: attachment.text,
7171
+ description: attachment.description
7172
+ }
7173
+ ]
7174
+ };
7175
+ if (attachment.kind === "pdf" && attachment.base64) {
7176
+ merged.pdfBase64 = attachment.base64;
7177
+ }
7178
+ if (attachment.kind === "image" && attachment.base64) {
7179
+ merged.images = [
7180
+ {
7181
+ imageBase64: attachment.base64,
7182
+ mimeType: attachment.mimeType ?? "image/jpeg"
7183
+ }
7184
+ ];
7185
+ }
7186
+ return merged;
7187
+ }
7188
+ function buildAttachmentEvidenceText(attachment, interpretation) {
7189
+ const lines = [
7190
+ `Attachment kind: ${attachment.kind}`,
7191
+ attachment.name ? `Attachment name: ${attachment.name}` : null,
7192
+ attachment.mimeType ? `MIME type: ${attachment.mimeType}` : null,
7193
+ attachment.description ? `Caller description: ${attachment.description}` : null,
7194
+ `Summary: ${interpretation.summary}`,
7195
+ interpretation.extractedFacts.length > 0 ? `Extracted facts:
7196
+ ${interpretation.extractedFacts.map((fact) => `- ${fact}`).join("\n")}` : null,
7197
+ interpretation.recommendedFocus.length > 0 ? `Important follow-up details:
7198
+ ${interpretation.recommendedFocus.map((item) => `- ${item}`).join("\n")}` : null,
7199
+ attachment.kind === "text" && attachment.text ? `Original text:
7200
+ ${attachment.text}` : null
7201
+ ];
7202
+ return lines.filter(Boolean).join("\n");
7203
+ }
7204
+ async function interpretAttachments(params) {
7205
+ const { attachments = [], question, generateObject, providerOptions, log, onUsage } = params;
7206
+ if (attachments.length === 0) {
7207
+ return { evidence: [] };
7208
+ }
7209
+ const evidence = [];
7210
+ for (const [index, attachment] of attachments.entries()) {
7211
+ const id = attachmentSourceId(attachment, index);
7212
+ if (attachment.kind === "text" && attachment.text) {
7213
+ const textEvidence = buildAttachmentEvidenceText(attachment, {
7214
+ summary: attachment.description ?? "User supplied text context.",
7215
+ extractedFacts: [attachment.text],
7216
+ recommendedFocus: [],
7217
+ confidence: 1
7218
+ });
7219
+ evidence.push({
7220
+ source: "attachment",
7221
+ attachmentId: id,
7222
+ chunkId: id,
7223
+ documentId: id,
7224
+ text: textEvidence,
7225
+ relevance: 0.95,
7226
+ metadata: [
7227
+ { key: "kind", value: attachment.kind },
7228
+ ...attachment.name ? [{ key: "name", value: attachment.name }] : []
7229
+ ]
7230
+ });
7231
+ continue;
7232
+ }
7233
+ const prompt = buildInterpretAttachmentPrompt(question, attachment);
7234
+ const { object, usage } = await safeGenerateObject(
7235
+ generateObject,
7236
+ {
7237
+ prompt,
7238
+ schema: AttachmentInterpretationSchema,
7239
+ maxTokens: 2048,
7240
+ providerOptions: buildAttachmentProviderOptions(attachment, providerOptions)
7241
+ },
7242
+ {
7243
+ fallback: {
7244
+ summary: attachment.description ?? `User supplied ${attachment.kind} attachment.`,
7245
+ extractedFacts: [],
7246
+ recommendedFocus: [],
7247
+ confidence: 0.2
7248
+ },
7249
+ log,
7250
+ onError: (error, attempt) => log?.(`Attachment interpretation attempt ${attempt + 1} failed for "${attachment.name ?? id}": ${error}`)
7251
+ }
7252
+ );
7253
+ onUsage?.(usage);
7254
+ evidence.push({
7255
+ source: "attachment",
7256
+ attachmentId: id,
7257
+ chunkId: id,
7258
+ documentId: id,
7259
+ text: buildAttachmentEvidenceText(attachment, object),
7260
+ relevance: Math.max(0.7, object.confidence),
7261
+ metadata: [
7262
+ { key: "kind", value: attachment.kind },
7263
+ ...attachment.name ? [{ key: "name", value: attachment.name }] : []
7264
+ ]
7265
+ });
7266
+ }
7267
+ const contextSummary = evidence.map((item, index) => `Attachment ${index + 1}:
7268
+ ${item.text}`).join("\n\n");
7269
+ return { evidence, contextSummary };
7270
+ }
7271
+
7101
7272
  // src/query/coordinator.ts
7102
7273
  function createQueryAgent(config) {
7103
7274
  const {
@@ -7125,13 +7296,23 @@ function createQueryAgent(config) {
7125
7296
  }
7126
7297
  async function query(input) {
7127
7298
  totalUsage = { inputTokens: 0, outputTokens: 0 };
7128
- const { question, conversationId, context } = input;
7299
+ const { question, conversationId, context, attachments } = input;
7129
7300
  const pipelineCtx = createPipelineContext({
7130
7301
  id: `query-${Date.now()}`
7131
7302
  });
7303
+ onProgress?.("Interpreting attachments...");
7304
+ const { evidence: attachmentEvidence, contextSummary: attachmentContext } = await interpretAttachments({
7305
+ attachments,
7306
+ question,
7307
+ generateObject,
7308
+ providerOptions,
7309
+ log,
7310
+ onUsage: trackUsage
7311
+ });
7312
+ await pipelineCtx.save("attachments", { attachmentEvidence });
7132
7313
  onProgress?.("Classifying query...");
7133
- const classification = await classify(question, conversationId);
7134
- await pipelineCtx.save("classify", { classification });
7314
+ const classification = await classify(question, conversationId, attachmentContext);
7315
+ await pipelineCtx.save("classify", { classification, attachmentEvidence });
7135
7316
  onProgress?.(`Retrieving evidence for ${classification.subQuestions.length} sub-question(s)...`);
7136
7317
  const retrieverConfig = {
7137
7318
  documentStore,
@@ -7144,8 +7325,8 @@ function createQueryAgent(config) {
7144
7325
  (sq) => limit(() => retrieve(sq, conversationId, retrieverConfig))
7145
7326
  )
7146
7327
  );
7147
- const allEvidence = retrievalResults.flatMap((r) => r.evidence);
7148
- await pipelineCtx.save("retrieve", { classification, evidence: allEvidence });
7328
+ const allEvidence = [...attachmentEvidence, ...retrievalResults.flatMap((r) => r.evidence)];
7329
+ await pipelineCtx.save("retrieve", { classification, attachmentEvidence, evidence: allEvidence });
7149
7330
  onProgress?.("Reasoning over evidence...");
7150
7331
  const reasonerConfig = { generateObject, providerOptions };
7151
7332
  const reasonResults = await Promise.allSettled(
@@ -7154,7 +7335,7 @@ function createQueryAgent(config) {
7154
7335
  const { subAnswer, usage } = await reason(
7155
7336
  sq.question,
7156
7337
  sq.intent,
7157
- retrievalResults[i].evidence,
7338
+ [...attachmentEvidence, ...retrievalResults[i].evidence],
7158
7339
  reasonerConfig
7159
7340
  );
7160
7341
  trackUsage(usage);
@@ -7178,7 +7359,7 @@ function createQueryAgent(config) {
7178
7359
  });
7179
7360
  }
7180
7361
  }
7181
- await pipelineCtx.save("reason", { classification, evidence: allEvidence, subAnswers });
7362
+ await pipelineCtx.save("reason", { classification, attachmentEvidence, evidence: allEvidence, subAnswers });
7182
7363
  onProgress?.("Verifying answer grounding...");
7183
7364
  const verifierConfig = { generateObject, providerOptions };
7184
7365
  const verifyRounds = [];
@@ -7226,7 +7407,7 @@ function createQueryAgent(config) {
7226
7407
  const { subAnswer, usage: u } = await reason(
7227
7408
  sq.question,
7228
7409
  sq.intent,
7229
- retryRetrievals[i].evidence,
7410
+ [...attachmentEvidence, ...retryRetrievals[i].evidence],
7230
7411
  reasonerConfig
7231
7412
  );
7232
7413
  trackUsage(u);
@@ -7261,6 +7442,7 @@ function createQueryAgent(config) {
7261
7442
  });
7262
7443
  await pipelineCtx.save("review", {
7263
7444
  classification,
7445
+ attachmentEvidence,
7264
7446
  evidence: allEvidence,
7265
7447
  subAnswers,
7266
7448
  reviewReport
@@ -7293,7 +7475,7 @@ function createQueryAgent(config) {
7293
7475
  }
7294
7476
  return { ...queryResult, tokenUsage: totalUsage, reviewReport };
7295
7477
  }
7296
- async function classify(question, conversationId) {
7478
+ async function classify(question, conversationId, attachmentContext) {
7297
7479
  let conversationContext;
7298
7480
  if (conversationId) {
7299
7481
  try {
@@ -7304,7 +7486,7 @@ function createQueryAgent(config) {
7304
7486
  } catch {
7305
7487
  }
7306
7488
  }
7307
- const prompt = buildQueryClassifyPrompt(question, conversationContext);
7489
+ const prompt = buildQueryClassifyPrompt(question, conversationContext, attachmentContext);
7308
7490
  const { object, usage } = await safeGenerateObject(
7309
7491
  generateObject,
7310
7492
  {
@@ -7520,6 +7702,7 @@ var AGENT_TOOLS = [
7520
7702
  ApplicationQualityReportSchema,
7521
7703
  ApplicationQualityRoundSchema,
7522
7704
  ApplicationStateSchema,
7705
+ AttachmentInterpretationSchema,
7523
7706
  AuditTypeSchema,
7524
7707
  AutoFillMatchSchema,
7525
7708
  AutoFillResultSchema,
@@ -7641,6 +7824,8 @@ var AGENT_TOOLS = [
7641
7824
  ProducerInfoSchema,
7642
7825
  ProfessionalLiabilityDeclarationsSchema,
7643
7826
  QUOTE_SECTION_TYPES,
7827
+ QueryAttachmentKindSchema,
7828
+ QueryAttachmentSchema,
7644
7829
  QueryClassifyResultSchema,
7645
7830
  QueryIntentSchema,
7646
7831
  QueryResultSchema,
@@ -7699,6 +7884,7 @@ var AGENT_TOOLS = [
7699
7884
  buildFormattingPrompt,
7700
7885
  buildIdentityPrompt,
7701
7886
  buildIntentPrompt,
7887
+ buildInterpretAttachmentPrompt,
7702
7888
  buildLookupFillPrompt,
7703
7889
  buildQueryClassifyPrompt,
7704
7890
  buildQuestionBatchPrompt,