@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/README.md +49 -1
- package/dist/index.d.mts +198 -11
- package/dist/index.d.ts +198 -11
- package/dist/index.js +316 -17
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +311 -17
- package/dist/index.mjs.map +1 -1
- package/dist/storage-sqlite.d.mts +56 -0
- package/dist/storage-sqlite.d.ts +56 -0
- package/package.json +2 -6
package/dist/index.mjs
CHANGED
|
@@ -1220,6 +1220,12 @@ var PremiumLineSchema = z16.object({
|
|
|
1220
1220
|
line: z16.string(),
|
|
1221
1221
|
amount: z16.string()
|
|
1222
1222
|
});
|
|
1223
|
+
var AuxiliaryFactSchema = z16.object({
|
|
1224
|
+
key: z16.string(),
|
|
1225
|
+
value: z16.string(),
|
|
1226
|
+
subject: z16.string().optional(),
|
|
1227
|
+
context: z16.string().optional()
|
|
1228
|
+
});
|
|
1223
1229
|
var BaseDocumentFields = {
|
|
1224
1230
|
id: z16.string(),
|
|
1225
1231
|
carrier: z16.string(),
|
|
@@ -1285,7 +1291,8 @@ var BaseDocumentFields = {
|
|
|
1285
1291
|
individualClaims: z16.array(ClaimRecordSchema).optional(),
|
|
1286
1292
|
experienceMod: ExperienceModSchema.optional(),
|
|
1287
1293
|
cancellationNoticeDays: z16.number().optional(),
|
|
1288
|
-
nonrenewalNoticeDays: z16.number().optional()
|
|
1294
|
+
nonrenewalNoticeDays: z16.number().optional(),
|
|
1295
|
+
supplementaryFacts: z16.array(AuxiliaryFactSchema).optional()
|
|
1289
1296
|
};
|
|
1290
1297
|
var PolicyDocumentSchema = z16.object({
|
|
1291
1298
|
...BaseDocumentFields,
|
|
@@ -1956,6 +1963,7 @@ function assembleDocument(documentId, documentType, memory) {
|
|
|
1956
1963
|
...sanitizeNulls(coverages ?? {}),
|
|
1957
1964
|
...sanitizeNulls(premium ?? {}),
|
|
1958
1965
|
...sanitizeNulls(supplementary ?? {}),
|
|
1966
|
+
supplementaryFacts: supplementary?.auxiliaryFacts,
|
|
1959
1967
|
endorsements: endorsements?.endorsements,
|
|
1960
1968
|
exclusions: exclusions?.exclusions,
|
|
1961
1969
|
conditions: conditions?.conditions,
|
|
@@ -2308,6 +2316,43 @@ Total Cost: ${doc.totalCost}` : ""}`,
|
|
|
2308
2316
|
metadata: stringMetadata({ premium: doc.premium, documentType: doc.type })
|
|
2309
2317
|
});
|
|
2310
2318
|
}
|
|
2319
|
+
const supplementaryLines = [
|
|
2320
|
+
...doc.claimsContacts?.map((contact) => `Claims Contact: ${[
|
|
2321
|
+
contact.name,
|
|
2322
|
+
contact.phone,
|
|
2323
|
+
contact.email,
|
|
2324
|
+
contact.hours
|
|
2325
|
+
].filter(Boolean).join(" | ")}`) ?? [],
|
|
2326
|
+
...doc.regulatoryContacts?.map((contact) => `Regulatory Contact: ${[
|
|
2327
|
+
contact.name,
|
|
2328
|
+
contact.phone,
|
|
2329
|
+
contact.email
|
|
2330
|
+
].filter(Boolean).join(" | ")}`) ?? [],
|
|
2331
|
+
...doc.thirdPartyAdministrators?.map((contact) => `TPA: ${[
|
|
2332
|
+
contact.name,
|
|
2333
|
+
contact.phone,
|
|
2334
|
+
contact.email
|
|
2335
|
+
].filter(Boolean).join(" | ")}`) ?? [],
|
|
2336
|
+
...doc.supplementaryFacts?.map((fact) => [
|
|
2337
|
+
fact.subject ? `Subject: ${fact.subject}` : null,
|
|
2338
|
+
`${fact.key}: ${fact.value}`,
|
|
2339
|
+
fact.context ? `Context: ${fact.context}` : null
|
|
2340
|
+
].filter(Boolean).join(" | ")) ?? [],
|
|
2341
|
+
doc.cancellationNoticeDays != null ? `Cancellation Notice Days: ${doc.cancellationNoticeDays}` : null,
|
|
2342
|
+
doc.nonrenewalNoticeDays != null ? `Nonrenewal Notice Days: ${doc.nonrenewalNoticeDays}` : null
|
|
2343
|
+
].filter((line) => Boolean(line));
|
|
2344
|
+
if (supplementaryLines.length > 0) {
|
|
2345
|
+
chunks.push({
|
|
2346
|
+
id: `${docId}:supplementary:0`,
|
|
2347
|
+
documentId: docId,
|
|
2348
|
+
type: "supplementary",
|
|
2349
|
+
text: supplementaryLines.join("\n"),
|
|
2350
|
+
metadata: stringMetadata({
|
|
2351
|
+
documentType: doc.type,
|
|
2352
|
+
supplementaryFactCount: doc.supplementaryFacts?.length
|
|
2353
|
+
})
|
|
2354
|
+
});
|
|
2355
|
+
}
|
|
2311
2356
|
return chunks;
|
|
2312
2357
|
}
|
|
2313
2358
|
|
|
@@ -2391,6 +2436,32 @@ function mergeArrayPayload(existing, incoming, arrayKey, keyFn) {
|
|
|
2391
2436
|
merged[arrayKey] = mergeUniqueObjects(existingItems, incomingItems, keyFn);
|
|
2392
2437
|
return merged;
|
|
2393
2438
|
}
|
|
2439
|
+
function mergeSupplementary(existing, incoming) {
|
|
2440
|
+
const merged = mergeShallowPreferPresent(existing, incoming);
|
|
2441
|
+
const mergeContactArray = (arrayKey) => {
|
|
2442
|
+
const existingItems = Array.isArray(existing[arrayKey]) ? existing[arrayKey] : [];
|
|
2443
|
+
const incomingItems = Array.isArray(incoming[arrayKey]) ? incoming[arrayKey] : [];
|
|
2444
|
+
merged[arrayKey] = mergeUniqueObjects(existingItems, incomingItems, (item) => [
|
|
2445
|
+
String(item.name ?? "").toLowerCase(),
|
|
2446
|
+
String(item.phone ?? "").toLowerCase(),
|
|
2447
|
+
String(item.email ?? "").toLowerCase(),
|
|
2448
|
+
String(item.address ?? "").toLowerCase(),
|
|
2449
|
+
String(item.type ?? "").toLowerCase()
|
|
2450
|
+
].join("|"));
|
|
2451
|
+
};
|
|
2452
|
+
mergeContactArray("regulatoryContacts");
|
|
2453
|
+
mergeContactArray("claimsContacts");
|
|
2454
|
+
mergeContactArray("thirdPartyAdministrators");
|
|
2455
|
+
const existingFacts = Array.isArray(existing.auxiliaryFacts) ? existing.auxiliaryFacts : [];
|
|
2456
|
+
const incomingFacts = Array.isArray(incoming.auxiliaryFacts) ? incoming.auxiliaryFacts : [];
|
|
2457
|
+
merged.auxiliaryFacts = mergeUniqueObjects(existingFacts, incomingFacts, (item) => [
|
|
2458
|
+
String(item.key ?? "").toLowerCase(),
|
|
2459
|
+
String(item.value ?? "").toLowerCase(),
|
|
2460
|
+
String(item.subject ?? "").toLowerCase(),
|
|
2461
|
+
String(item.context ?? "").toLowerCase()
|
|
2462
|
+
].join("|"));
|
|
2463
|
+
return merged;
|
|
2464
|
+
}
|
|
2394
2465
|
function mergeExtractorResult(extractorName, existing, incoming) {
|
|
2395
2466
|
if (!existing) return incoming;
|
|
2396
2467
|
if (!incoming) return existing;
|
|
@@ -2401,9 +2472,10 @@ function mergeExtractorResult(extractorName, existing, incoming) {
|
|
|
2401
2472
|
case "carrier_info":
|
|
2402
2473
|
case "named_insured":
|
|
2403
2474
|
case "loss_history":
|
|
2404
|
-
case "supplementary":
|
|
2405
2475
|
case "premium_breakdown":
|
|
2406
2476
|
return mergeShallowPreferPresent(current, next);
|
|
2477
|
+
case "supplementary":
|
|
2478
|
+
return mergeSupplementary(current, next);
|
|
2407
2479
|
case "coverage_limits":
|
|
2408
2480
|
return mergeCoverageLimits(current, next);
|
|
2409
2481
|
case "declarations":
|
|
@@ -4000,15 +4072,22 @@ var ContactSchema2 = z33.object({
|
|
|
4000
4072
|
address: z33.string().optional().describe("Mailing address"),
|
|
4001
4073
|
type: z33.string().optional().describe("Contact type, e.g. 'State Department of Insurance'")
|
|
4002
4074
|
});
|
|
4075
|
+
var AuxiliaryFactSchema2 = z33.object({
|
|
4076
|
+
key: z33.string().describe("Normalized machine-readable fact key, e.g. 'policyholder_age' or 'insured_name'"),
|
|
4077
|
+
value: z33.string().describe("Concrete extracted fact value"),
|
|
4078
|
+
subject: z33.string().optional().describe("Person, entity, vehicle, property, or schedule item this fact belongs to"),
|
|
4079
|
+
context: z33.string().optional().describe("Short disambiguating context, such as 'Driver Schedule' or 'Named Insured'")
|
|
4080
|
+
});
|
|
4003
4081
|
var SupplementarySchema = z33.object({
|
|
4004
4082
|
regulatoryContacts: z33.array(ContactSchema2).optional().describe("Regulatory body contacts (state department of insurance, ombudsman)"),
|
|
4005
4083
|
claimsContacts: z33.array(ContactSchema2).optional().describe("Claims reporting contacts and instructions"),
|
|
4006
4084
|
thirdPartyAdministrators: z33.array(ContactSchema2).optional().describe("Third-party administrators for claims handling"),
|
|
4007
4085
|
cancellationNoticeDays: z33.number().optional().describe("Required notice period for cancellation in days"),
|
|
4008
|
-
nonrenewalNoticeDays: z33.number().optional().describe("Required notice period for nonrenewal in days")
|
|
4086
|
+
nonrenewalNoticeDays: z33.number().optional().describe("Required notice period for nonrenewal in days"),
|
|
4087
|
+
auxiliaryFacts: z33.array(AuxiliaryFactSchema2).optional().describe("Additional retrieval-only facts that do not fit the strict primary schema")
|
|
4009
4088
|
});
|
|
4010
4089
|
function buildSupplementaryPrompt() {
|
|
4011
|
-
return `You are an expert insurance document analyst. Extract supplementary
|
|
4090
|
+
return `You are an expert insurance document analyst. Extract supplementary, retrieval-only information from this document.
|
|
4012
4091
|
|
|
4013
4092
|
Focus on:
|
|
4014
4093
|
- Regulatory contacts: state department of insurance, regulatory bodies, ombudsman offices \u2014 with phone, email, address
|
|
@@ -4018,9 +4097,19 @@ Focus on:
|
|
|
4018
4097
|
- Nonrenewal notice period in days
|
|
4019
4098
|
- Complaint filing procedures and contacts
|
|
4020
4099
|
- Governing law or jurisdiction provisions
|
|
4100
|
+
- Additional policy-specific facts that are useful for memory and retrieval even if they do not belong in the strict primary schema
|
|
4021
4101
|
|
|
4022
4102
|
Look for regulatory notices, complaint contact sections, claims reporting instructions, and cancellation/nonrenewal provisions throughout the document.
|
|
4023
4103
|
|
|
4104
|
+
For auxiliaryFacts:
|
|
4105
|
+
- Capture concrete, policy-specific facts as structured key/value pairs.
|
|
4106
|
+
- 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.
|
|
4107
|
+
- Use short normalized keys like "policyholder_name", "policyholder_age", "insured_name", "driver_age", "driver_date_of_birth", "garaging_zip", "vehicle_principal_driver".
|
|
4108
|
+
- Use subject when the fact belongs to a specific person, vehicle, property, or scheduled item.
|
|
4109
|
+
- Do not invent facts.
|
|
4110
|
+
- Do not include vague boilerplate or generic form language.
|
|
4111
|
+
- Do not repeat large narrative excerpts; keep facts atomic.
|
|
4112
|
+
|
|
4024
4113
|
Return JSON only.`;
|
|
4025
4114
|
}
|
|
4026
4115
|
|
|
@@ -4747,6 +4836,28 @@ function createExtractor(config) {
|
|
|
4747
4836
|
mergeMemoryResult(result.name, result.data, memory);
|
|
4748
4837
|
}
|
|
4749
4838
|
}
|
|
4839
|
+
const supplementaryExtractor = getExtractor("supplementary");
|
|
4840
|
+
if (supplementaryExtractor) {
|
|
4841
|
+
onProgress?.("Extracting supplementary retrieval facts...");
|
|
4842
|
+
try {
|
|
4843
|
+
const supplementaryResult = await runExtractor({
|
|
4844
|
+
name: "supplementary",
|
|
4845
|
+
prompt: supplementaryExtractor.buildPrompt(),
|
|
4846
|
+
schema: supplementaryExtractor.schema,
|
|
4847
|
+
pdfBase64,
|
|
4848
|
+
startPage: 1,
|
|
4849
|
+
endPage: pageCount,
|
|
4850
|
+
generateObject,
|
|
4851
|
+
convertPdfToImages,
|
|
4852
|
+
maxTokens: supplementaryExtractor.maxTokens ?? 4096,
|
|
4853
|
+
providerOptions
|
|
4854
|
+
});
|
|
4855
|
+
trackUsage(supplementaryResult.usage);
|
|
4856
|
+
mergeMemoryResult(supplementaryResult.name, supplementaryResult.data, memory);
|
|
4857
|
+
} catch (error) {
|
|
4858
|
+
await log?.(`Supplementary extractor failed: ${error}`);
|
|
4859
|
+
}
|
|
4860
|
+
}
|
|
4750
4861
|
await pipelineCtx.save("extract", {
|
|
4751
4862
|
id,
|
|
4752
4863
|
pageCount,
|
|
@@ -6336,7 +6447,7 @@ Respond with the explanation text only \u2014 no JSON, no field ID, no extra for
|
|
|
6336
6447
|
}
|
|
6337
6448
|
|
|
6338
6449
|
// src/prompts/query/classify.ts
|
|
6339
|
-
function buildQueryClassifyPrompt(question, conversationContext) {
|
|
6450
|
+
function buildQueryClassifyPrompt(question, conversationContext, attachmentContext) {
|
|
6340
6451
|
return `You are a query classifier for an insurance document intelligence system.
|
|
6341
6452
|
|
|
6342
6453
|
Analyze the user's question and produce a structured classification.
|
|
@@ -6346,6 +6457,9 @@ ${question}
|
|
|
6346
6457
|
${conversationContext ? `
|
|
6347
6458
|
CONVERSATION CONTEXT:
|
|
6348
6459
|
${conversationContext}` : ""}
|
|
6460
|
+
${attachmentContext ? `
|
|
6461
|
+
ATTACHMENT CONTEXT:
|
|
6462
|
+
${attachmentContext}` : ""}
|
|
6349
6463
|
|
|
6350
6464
|
INSTRUCTIONS:
|
|
6351
6465
|
|
|
@@ -6366,6 +6480,7 @@ INSTRUCTIONS:
|
|
|
6366
6480
|
- requiresDocumentLookup: true if a specific document needs to be fetched by ID/number/carrier
|
|
6367
6481
|
- requiresChunkSearch: true if semantic search over document chunks is needed
|
|
6368
6482
|
- requiresConversationHistory: true if the question references prior conversation
|
|
6483
|
+
- 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
|
|
6369
6484
|
|
|
6370
6485
|
CHUNK TYPES (for chunkTypes filter):
|
|
6371
6486
|
carrier_info, named_insured, coverage, endorsement, exclusion, condition, section, declaration, loss_history, premium, supplementary
|
|
@@ -6407,6 +6522,16 @@ var QueryIntentSchema = z35.enum([
|
|
|
6407
6522
|
"claims_inquiry",
|
|
6408
6523
|
"general_knowledge"
|
|
6409
6524
|
]);
|
|
6525
|
+
var QueryAttachmentKindSchema = z35.enum(["image", "pdf", "text"]);
|
|
6526
|
+
var QueryAttachmentSchema = z35.object({
|
|
6527
|
+
id: z35.string().optional().describe("Optional stable attachment ID from the caller"),
|
|
6528
|
+
kind: QueryAttachmentKindSchema,
|
|
6529
|
+
name: z35.string().optional().describe("Original filename or user-facing label"),
|
|
6530
|
+
mimeType: z35.string().optional().describe("MIME type such as image/jpeg or application/pdf"),
|
|
6531
|
+
base64: z35.string().optional().describe("Base64-encoded file content for image/pdf attachments"),
|
|
6532
|
+
text: z35.string().optional().describe("Plain-text attachment content when available"),
|
|
6533
|
+
description: z35.string().optional().describe("Caller-provided description of the attachment")
|
|
6534
|
+
});
|
|
6410
6535
|
var SubQuestionSchema = z35.object({
|
|
6411
6536
|
question: z35.string().describe("Atomic sub-question to retrieve and answer independently"),
|
|
6412
6537
|
intent: QueryIntentSchema,
|
|
@@ -6427,14 +6552,21 @@ var QueryClassifyResultSchema = z35.object({
|
|
|
6427
6552
|
requiresConversationHistory: z35.boolean().describe("Whether conversation history is relevant")
|
|
6428
6553
|
});
|
|
6429
6554
|
var EvidenceItemSchema = z35.object({
|
|
6430
|
-
source: z35.enum(["chunk", "document", "conversation"]),
|
|
6555
|
+
source: z35.enum(["chunk", "document", "conversation", "attachment"]),
|
|
6431
6556
|
chunkId: z35.string().optional(),
|
|
6432
6557
|
documentId: z35.string().optional(),
|
|
6433
6558
|
turnId: z35.string().optional(),
|
|
6559
|
+
attachmentId: z35.string().optional(),
|
|
6434
6560
|
text: z35.string().describe("Text excerpt from the source"),
|
|
6435
6561
|
relevance: z35.number().min(0).max(1),
|
|
6436
6562
|
metadata: z35.array(z35.object({ key: z35.string(), value: z35.string() })).optional()
|
|
6437
6563
|
});
|
|
6564
|
+
var AttachmentInterpretationSchema = z35.object({
|
|
6565
|
+
summary: z35.string().describe("Concise summary of what the attachment shows or contains"),
|
|
6566
|
+
extractedFacts: z35.array(z35.string()).describe("Specific observable or document facts grounded in the attachment"),
|
|
6567
|
+
recommendedFocus: z35.array(z35.string()).describe("Important details to incorporate when answering follow-up questions"),
|
|
6568
|
+
confidence: z35.number().min(0).max(1)
|
|
6569
|
+
});
|
|
6438
6570
|
var RetrievalResultSchema = z35.object({
|
|
6439
6571
|
subQuestion: z35.string(),
|
|
6440
6572
|
evidence: z35.array(EvidenceItemSchema)
|
|
@@ -6755,7 +6887,7 @@ async function verify(originalQuestion, subAnswers, allEvidence, config) {
|
|
|
6755
6887
|
|
|
6756
6888
|
// src/query/quality.ts
|
|
6757
6889
|
function sourceIdForEvidence(evidence) {
|
|
6758
|
-
return evidence.chunkId ?? evidence.documentId ?? evidence.turnId;
|
|
6890
|
+
return evidence.chunkId ?? evidence.documentId ?? evidence.turnId ?? evidence.attachmentId;
|
|
6759
6891
|
}
|
|
6760
6892
|
function citationSourceId(citation) {
|
|
6761
6893
|
return citation.chunkId || citation.documentId;
|
|
@@ -6859,6 +6991,152 @@ function buildQueryReviewReport(params) {
|
|
|
6859
6991
|
};
|
|
6860
6992
|
}
|
|
6861
6993
|
|
|
6994
|
+
// src/prompts/query/interpret-attachment.ts
|
|
6995
|
+
function buildInterpretAttachmentPrompt(question, attachment) {
|
|
6996
|
+
const attachmentLabel = attachment.name ?? attachment.id ?? "attachment";
|
|
6997
|
+
const descriptor = [
|
|
6998
|
+
`Attachment: ${attachmentLabel}`,
|
|
6999
|
+
`Kind: ${attachment.kind}`,
|
|
7000
|
+
attachment.mimeType ? `MIME type: ${attachment.mimeType}` : null,
|
|
7001
|
+
attachment.description ? `Caller description: ${attachment.description}` : null
|
|
7002
|
+
].filter(Boolean).join("\n");
|
|
7003
|
+
return `You are interpreting a user-supplied attachment for an insurance-support question.
|
|
7004
|
+
|
|
7005
|
+
USER QUESTION:
|
|
7006
|
+
${question}
|
|
7007
|
+
|
|
7008
|
+
ATTACHMENT METADATA:
|
|
7009
|
+
${descriptor}
|
|
7010
|
+
|
|
7011
|
+
${attachment.kind === "text" && attachment.text ? `ATTACHMENT TEXT:
|
|
7012
|
+
${attachment.text}
|
|
7013
|
+
` : "The attachment content is provided separately as a file or image input.\n"}
|
|
7014
|
+
INSTRUCTIONS:
|
|
7015
|
+
1. Describe what the attachment appears to show or contain in a concise summary.
|
|
7016
|
+
2. Extract concrete facts that may matter when answering the user's question.
|
|
7017
|
+
3. Note the most important details to carry forward into follow-up questions.
|
|
7018
|
+
4. If the attachment is a document, identify the key business or insurance details visible.
|
|
7019
|
+
5. If the attachment is a photo of damage or a real-world issue, describe the observable issue without guessing beyond what is visible.
|
|
7020
|
+
6. Do not invent unreadable text. If something is unclear, say so in the summary or extracted facts.
|
|
7021
|
+
|
|
7022
|
+
Respond with the structured interpretation.`;
|
|
7023
|
+
}
|
|
7024
|
+
|
|
7025
|
+
// src/query/multimodal.ts
|
|
7026
|
+
function attachmentSourceId(attachment, index) {
|
|
7027
|
+
return attachment.id ?? `attachment-${index + 1}`;
|
|
7028
|
+
}
|
|
7029
|
+
function buildAttachmentProviderOptions(attachment, providerOptions) {
|
|
7030
|
+
const merged = {
|
|
7031
|
+
...providerOptions,
|
|
7032
|
+
attachments: [
|
|
7033
|
+
{
|
|
7034
|
+
kind: attachment.kind,
|
|
7035
|
+
name: attachment.name,
|
|
7036
|
+
mimeType: attachment.mimeType,
|
|
7037
|
+
base64: attachment.base64,
|
|
7038
|
+
text: attachment.text,
|
|
7039
|
+
description: attachment.description
|
|
7040
|
+
}
|
|
7041
|
+
]
|
|
7042
|
+
};
|
|
7043
|
+
if (attachment.kind === "pdf" && attachment.base64) {
|
|
7044
|
+
merged.pdfBase64 = attachment.base64;
|
|
7045
|
+
}
|
|
7046
|
+
if (attachment.kind === "image" && attachment.base64) {
|
|
7047
|
+
merged.images = [
|
|
7048
|
+
{
|
|
7049
|
+
imageBase64: attachment.base64,
|
|
7050
|
+
mimeType: attachment.mimeType ?? "image/jpeg"
|
|
7051
|
+
}
|
|
7052
|
+
];
|
|
7053
|
+
}
|
|
7054
|
+
return merged;
|
|
7055
|
+
}
|
|
7056
|
+
function buildAttachmentEvidenceText(attachment, interpretation) {
|
|
7057
|
+
const lines = [
|
|
7058
|
+
`Attachment kind: ${attachment.kind}`,
|
|
7059
|
+
attachment.name ? `Attachment name: ${attachment.name}` : null,
|
|
7060
|
+
attachment.mimeType ? `MIME type: ${attachment.mimeType}` : null,
|
|
7061
|
+
attachment.description ? `Caller description: ${attachment.description}` : null,
|
|
7062
|
+
`Summary: ${interpretation.summary}`,
|
|
7063
|
+
interpretation.extractedFacts.length > 0 ? `Extracted facts:
|
|
7064
|
+
${interpretation.extractedFacts.map((fact) => `- ${fact}`).join("\n")}` : null,
|
|
7065
|
+
interpretation.recommendedFocus.length > 0 ? `Important follow-up details:
|
|
7066
|
+
${interpretation.recommendedFocus.map((item) => `- ${item}`).join("\n")}` : null,
|
|
7067
|
+
attachment.kind === "text" && attachment.text ? `Original text:
|
|
7068
|
+
${attachment.text}` : null
|
|
7069
|
+
];
|
|
7070
|
+
return lines.filter(Boolean).join("\n");
|
|
7071
|
+
}
|
|
7072
|
+
async function interpretAttachments(params) {
|
|
7073
|
+
const { attachments = [], question, generateObject, providerOptions, log, onUsage } = params;
|
|
7074
|
+
if (attachments.length === 0) {
|
|
7075
|
+
return { evidence: [] };
|
|
7076
|
+
}
|
|
7077
|
+
const evidence = [];
|
|
7078
|
+
for (const [index, attachment] of attachments.entries()) {
|
|
7079
|
+
const id = attachmentSourceId(attachment, index);
|
|
7080
|
+
if (attachment.kind === "text" && attachment.text) {
|
|
7081
|
+
const textEvidence = buildAttachmentEvidenceText(attachment, {
|
|
7082
|
+
summary: attachment.description ?? "User supplied text context.",
|
|
7083
|
+
extractedFacts: [attachment.text],
|
|
7084
|
+
recommendedFocus: [],
|
|
7085
|
+
confidence: 1
|
|
7086
|
+
});
|
|
7087
|
+
evidence.push({
|
|
7088
|
+
source: "attachment",
|
|
7089
|
+
attachmentId: id,
|
|
7090
|
+
chunkId: id,
|
|
7091
|
+
documentId: id,
|
|
7092
|
+
text: textEvidence,
|
|
7093
|
+
relevance: 0.95,
|
|
7094
|
+
metadata: [
|
|
7095
|
+
{ key: "kind", value: attachment.kind },
|
|
7096
|
+
...attachment.name ? [{ key: "name", value: attachment.name }] : []
|
|
7097
|
+
]
|
|
7098
|
+
});
|
|
7099
|
+
continue;
|
|
7100
|
+
}
|
|
7101
|
+
const prompt = buildInterpretAttachmentPrompt(question, attachment);
|
|
7102
|
+
const { object, usage } = await safeGenerateObject(
|
|
7103
|
+
generateObject,
|
|
7104
|
+
{
|
|
7105
|
+
prompt,
|
|
7106
|
+
schema: AttachmentInterpretationSchema,
|
|
7107
|
+
maxTokens: 2048,
|
|
7108
|
+
providerOptions: buildAttachmentProviderOptions(attachment, providerOptions)
|
|
7109
|
+
},
|
|
7110
|
+
{
|
|
7111
|
+
fallback: {
|
|
7112
|
+
summary: attachment.description ?? `User supplied ${attachment.kind} attachment.`,
|
|
7113
|
+
extractedFacts: [],
|
|
7114
|
+
recommendedFocus: [],
|
|
7115
|
+
confidence: 0.2
|
|
7116
|
+
},
|
|
7117
|
+
log,
|
|
7118
|
+
onError: (error, attempt) => log?.(`Attachment interpretation attempt ${attempt + 1} failed for "${attachment.name ?? id}": ${error}`)
|
|
7119
|
+
}
|
|
7120
|
+
);
|
|
7121
|
+
onUsage?.(usage);
|
|
7122
|
+
evidence.push({
|
|
7123
|
+
source: "attachment",
|
|
7124
|
+
attachmentId: id,
|
|
7125
|
+
chunkId: id,
|
|
7126
|
+
documentId: id,
|
|
7127
|
+
text: buildAttachmentEvidenceText(attachment, object),
|
|
7128
|
+
relevance: Math.max(0.7, object.confidence),
|
|
7129
|
+
metadata: [
|
|
7130
|
+
{ key: "kind", value: attachment.kind },
|
|
7131
|
+
...attachment.name ? [{ key: "name", value: attachment.name }] : []
|
|
7132
|
+
]
|
|
7133
|
+
});
|
|
7134
|
+
}
|
|
7135
|
+
const contextSummary = evidence.map((item, index) => `Attachment ${index + 1}:
|
|
7136
|
+
${item.text}`).join("\n\n");
|
|
7137
|
+
return { evidence, contextSummary };
|
|
7138
|
+
}
|
|
7139
|
+
|
|
6862
7140
|
// src/query/coordinator.ts
|
|
6863
7141
|
function createQueryAgent(config) {
|
|
6864
7142
|
const {
|
|
@@ -6886,13 +7164,23 @@ function createQueryAgent(config) {
|
|
|
6886
7164
|
}
|
|
6887
7165
|
async function query(input) {
|
|
6888
7166
|
totalUsage = { inputTokens: 0, outputTokens: 0 };
|
|
6889
|
-
const { question, conversationId, context } = input;
|
|
7167
|
+
const { question, conversationId, context, attachments } = input;
|
|
6890
7168
|
const pipelineCtx = createPipelineContext({
|
|
6891
7169
|
id: `query-${Date.now()}`
|
|
6892
7170
|
});
|
|
7171
|
+
onProgress?.("Interpreting attachments...");
|
|
7172
|
+
const { evidence: attachmentEvidence, contextSummary: attachmentContext } = await interpretAttachments({
|
|
7173
|
+
attachments,
|
|
7174
|
+
question,
|
|
7175
|
+
generateObject,
|
|
7176
|
+
providerOptions,
|
|
7177
|
+
log,
|
|
7178
|
+
onUsage: trackUsage
|
|
7179
|
+
});
|
|
7180
|
+
await pipelineCtx.save("attachments", { attachmentEvidence });
|
|
6893
7181
|
onProgress?.("Classifying query...");
|
|
6894
|
-
const classification = await classify(question, conversationId);
|
|
6895
|
-
await pipelineCtx.save("classify", { classification });
|
|
7182
|
+
const classification = await classify(question, conversationId, attachmentContext);
|
|
7183
|
+
await pipelineCtx.save("classify", { classification, attachmentEvidence });
|
|
6896
7184
|
onProgress?.(`Retrieving evidence for ${classification.subQuestions.length} sub-question(s)...`);
|
|
6897
7185
|
const retrieverConfig = {
|
|
6898
7186
|
documentStore,
|
|
@@ -6905,8 +7193,8 @@ function createQueryAgent(config) {
|
|
|
6905
7193
|
(sq) => limit(() => retrieve(sq, conversationId, retrieverConfig))
|
|
6906
7194
|
)
|
|
6907
7195
|
);
|
|
6908
|
-
const allEvidence = retrievalResults.flatMap((r) => r.evidence);
|
|
6909
|
-
await pipelineCtx.save("retrieve", { classification, evidence: allEvidence });
|
|
7196
|
+
const allEvidence = [...attachmentEvidence, ...retrievalResults.flatMap((r) => r.evidence)];
|
|
7197
|
+
await pipelineCtx.save("retrieve", { classification, attachmentEvidence, evidence: allEvidence });
|
|
6910
7198
|
onProgress?.("Reasoning over evidence...");
|
|
6911
7199
|
const reasonerConfig = { generateObject, providerOptions };
|
|
6912
7200
|
const reasonResults = await Promise.allSettled(
|
|
@@ -6915,7 +7203,7 @@ function createQueryAgent(config) {
|
|
|
6915
7203
|
const { subAnswer, usage } = await reason(
|
|
6916
7204
|
sq.question,
|
|
6917
7205
|
sq.intent,
|
|
6918
|
-
retrievalResults[i].evidence,
|
|
7206
|
+
[...attachmentEvidence, ...retrievalResults[i].evidence],
|
|
6919
7207
|
reasonerConfig
|
|
6920
7208
|
);
|
|
6921
7209
|
trackUsage(usage);
|
|
@@ -6939,7 +7227,7 @@ function createQueryAgent(config) {
|
|
|
6939
7227
|
});
|
|
6940
7228
|
}
|
|
6941
7229
|
}
|
|
6942
|
-
await pipelineCtx.save("reason", { classification, evidence: allEvidence, subAnswers });
|
|
7230
|
+
await pipelineCtx.save("reason", { classification, attachmentEvidence, evidence: allEvidence, subAnswers });
|
|
6943
7231
|
onProgress?.("Verifying answer grounding...");
|
|
6944
7232
|
const verifierConfig = { generateObject, providerOptions };
|
|
6945
7233
|
const verifyRounds = [];
|
|
@@ -6987,7 +7275,7 @@ function createQueryAgent(config) {
|
|
|
6987
7275
|
const { subAnswer, usage: u } = await reason(
|
|
6988
7276
|
sq.question,
|
|
6989
7277
|
sq.intent,
|
|
6990
|
-
retryRetrievals[i].evidence,
|
|
7278
|
+
[...attachmentEvidence, ...retryRetrievals[i].evidence],
|
|
6991
7279
|
reasonerConfig
|
|
6992
7280
|
);
|
|
6993
7281
|
trackUsage(u);
|
|
@@ -7022,6 +7310,7 @@ function createQueryAgent(config) {
|
|
|
7022
7310
|
});
|
|
7023
7311
|
await pipelineCtx.save("review", {
|
|
7024
7312
|
classification,
|
|
7313
|
+
attachmentEvidence,
|
|
7025
7314
|
evidence: allEvidence,
|
|
7026
7315
|
subAnswers,
|
|
7027
7316
|
reviewReport
|
|
@@ -7054,7 +7343,7 @@ function createQueryAgent(config) {
|
|
|
7054
7343
|
}
|
|
7055
7344
|
return { ...queryResult, tokenUsage: totalUsage, reviewReport };
|
|
7056
7345
|
}
|
|
7057
|
-
async function classify(question, conversationId) {
|
|
7346
|
+
async function classify(question, conversationId, attachmentContext) {
|
|
7058
7347
|
let conversationContext;
|
|
7059
7348
|
if (conversationId) {
|
|
7060
7349
|
try {
|
|
@@ -7065,7 +7354,7 @@ function createQueryAgent(config) {
|
|
|
7065
7354
|
} catch {
|
|
7066
7355
|
}
|
|
7067
7356
|
}
|
|
7068
|
-
const prompt = buildQueryClassifyPrompt(question, conversationContext);
|
|
7357
|
+
const prompt = buildQueryClassifyPrompt(question, conversationContext, attachmentContext);
|
|
7069
7358
|
const { object, usage } = await safeGenerateObject(
|
|
7070
7359
|
generateObject,
|
|
7071
7360
|
{
|
|
@@ -7280,9 +7569,11 @@ export {
|
|
|
7280
7569
|
ApplicationQualityReportSchema,
|
|
7281
7570
|
ApplicationQualityRoundSchema,
|
|
7282
7571
|
ApplicationStateSchema,
|
|
7572
|
+
AttachmentInterpretationSchema,
|
|
7283
7573
|
AuditTypeSchema,
|
|
7284
7574
|
AutoFillMatchSchema,
|
|
7285
7575
|
AutoFillResultSchema,
|
|
7576
|
+
AuxiliaryFactSchema,
|
|
7286
7577
|
BOAT_TYPES,
|
|
7287
7578
|
BindingAuthoritySchema,
|
|
7288
7579
|
BoatTypeSchema,
|
|
@@ -7401,6 +7692,8 @@ export {
|
|
|
7401
7692
|
ProducerInfoSchema,
|
|
7402
7693
|
ProfessionalLiabilityDeclarationsSchema,
|
|
7403
7694
|
QUOTE_SECTION_TYPES,
|
|
7695
|
+
QueryAttachmentKindSchema,
|
|
7696
|
+
QueryAttachmentSchema,
|
|
7404
7697
|
QueryClassifyResultSchema,
|
|
7405
7698
|
QueryIntentSchema,
|
|
7406
7699
|
QueryResultSchema,
|
|
@@ -7459,6 +7752,7 @@ export {
|
|
|
7459
7752
|
buildFormattingPrompt,
|
|
7460
7753
|
buildIdentityPrompt,
|
|
7461
7754
|
buildIntentPrompt,
|
|
7755
|
+
buildInterpretAttachmentPrompt,
|
|
7462
7756
|
buildLookupFillPrompt,
|
|
7463
7757
|
buildQueryClassifyPrompt,
|
|
7464
7758
|
buildQuestionBatchPrompt,
|