@claritylabs/cl-sdk 2.0.1 → 3.0.1
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 +12 -11
- package/dist/index.d.mts +692 -20
- package/dist/index.d.ts +692 -20
- package/dist/index.js +1385 -253
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1374 -253
- package/dist/index.mjs.map +1 -1
- package/dist/storage-sqlite.d.mts +104 -0
- package/dist/storage-sqlite.d.ts +104 -0
- package/dist/storage-sqlite.js +80 -0
- package/dist/storage-sqlite.js.map +1 -1
- package/dist/storage-sqlite.mjs +80 -0
- package/dist/storage-sqlite.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1407,6 +1407,8 @@ var DocumentAgentGuidanceSchema = z16.object({
|
|
|
1407
1407
|
sourceSpanIds: z16.array(z16.string()).optional()
|
|
1408
1408
|
});
|
|
1409
1409
|
var DocumentMetadataSchema = z16.object({
|
|
1410
|
+
sourceTreeVersion: z16.string().optional(),
|
|
1411
|
+
sourceTreeCanonical: z16.boolean().optional(),
|
|
1410
1412
|
formInventory: z16.array(FormReferenceSchema).optional(),
|
|
1411
1413
|
tableOfContents: z16.array(DocumentTableOfContentsEntrySchema).optional(),
|
|
1412
1414
|
pageMap: z16.array(DocumentPageMapEntrySchema).optional(),
|
|
@@ -2006,6 +2008,86 @@ var SourceChunkSchema = z20.object({
|
|
|
2006
2008
|
pageEnd: z20.number().int().positive().optional(),
|
|
2007
2009
|
metadata: z20.record(z20.string(), z20.string()).default({})
|
|
2008
2010
|
});
|
|
2011
|
+
var DocumentSourceNodeKindSchema = z20.enum([
|
|
2012
|
+
"document",
|
|
2013
|
+
"page_group",
|
|
2014
|
+
"page",
|
|
2015
|
+
"form",
|
|
2016
|
+
"endorsement",
|
|
2017
|
+
"section",
|
|
2018
|
+
"schedule",
|
|
2019
|
+
"clause",
|
|
2020
|
+
"table",
|
|
2021
|
+
"table_row",
|
|
2022
|
+
"table_cell",
|
|
2023
|
+
"text"
|
|
2024
|
+
]);
|
|
2025
|
+
var DocumentSourceNodeSchema = z20.object({
|
|
2026
|
+
id: z20.string().min(1),
|
|
2027
|
+
documentId: z20.string().min(1),
|
|
2028
|
+
parentId: z20.string().optional(),
|
|
2029
|
+
kind: DocumentSourceNodeKindSchema,
|
|
2030
|
+
title: z20.string(),
|
|
2031
|
+
description: z20.string(),
|
|
2032
|
+
textExcerpt: z20.string().optional(),
|
|
2033
|
+
sourceSpanIds: z20.array(z20.string().min(1)),
|
|
2034
|
+
pageStart: z20.number().int().positive().optional(),
|
|
2035
|
+
pageEnd: z20.number().int().positive().optional(),
|
|
2036
|
+
bbox: z20.array(SourceSpanBBoxSchema).optional(),
|
|
2037
|
+
order: z20.number().int().nonnegative(),
|
|
2038
|
+
path: z20.string(),
|
|
2039
|
+
metadata: z20.record(z20.string(), z20.unknown()).optional()
|
|
2040
|
+
});
|
|
2041
|
+
var SourceBackedValueSchema = z20.object({
|
|
2042
|
+
value: z20.string(),
|
|
2043
|
+
normalizedValue: z20.string().optional(),
|
|
2044
|
+
confidence: z20.enum(["low", "medium", "high"]).default("medium"),
|
|
2045
|
+
sourceNodeIds: z20.array(z20.string().min(1)).default([]),
|
|
2046
|
+
sourceSpanIds: z20.array(z20.string().min(1)).default([])
|
|
2047
|
+
});
|
|
2048
|
+
var OperationalCoverageLineSchema = z20.object({
|
|
2049
|
+
name: z20.string(),
|
|
2050
|
+
coverageCode: z20.string().optional(),
|
|
2051
|
+
limit: z20.string().optional(),
|
|
2052
|
+
deductible: z20.string().optional(),
|
|
2053
|
+
premium: z20.string().optional(),
|
|
2054
|
+
formNumber: z20.string().optional(),
|
|
2055
|
+
sectionRef: z20.string().optional(),
|
|
2056
|
+
sourceNodeIds: z20.array(z20.string().min(1)).default([]),
|
|
2057
|
+
sourceSpanIds: z20.array(z20.string().min(1)).default([])
|
|
2058
|
+
});
|
|
2059
|
+
var OperationalPartySchema = z20.object({
|
|
2060
|
+
role: z20.string(),
|
|
2061
|
+
name: z20.string(),
|
|
2062
|
+
sourceNodeIds: z20.array(z20.string().min(1)).default([]),
|
|
2063
|
+
sourceSpanIds: z20.array(z20.string().min(1)).default([])
|
|
2064
|
+
});
|
|
2065
|
+
var OperationalEndorsementSupportSchema = z20.object({
|
|
2066
|
+
kind: z20.string(),
|
|
2067
|
+
status: z20.enum(["supported", "excluded", "requires_review"]),
|
|
2068
|
+
summary: z20.string(),
|
|
2069
|
+
sourceNodeIds: z20.array(z20.string().min(1)).default([]),
|
|
2070
|
+
sourceSpanIds: z20.array(z20.string().min(1)).default([])
|
|
2071
|
+
});
|
|
2072
|
+
var PolicyOperationalProfileSchema = z20.object({
|
|
2073
|
+
documentType: z20.enum(["policy", "quote"]).default("policy"),
|
|
2074
|
+
policyTypes: z20.array(z20.string()).default(["other"]),
|
|
2075
|
+
policyNumber: SourceBackedValueSchema.optional(),
|
|
2076
|
+
namedInsured: SourceBackedValueSchema.optional(),
|
|
2077
|
+
insurer: SourceBackedValueSchema.optional(),
|
|
2078
|
+
broker: SourceBackedValueSchema.optional(),
|
|
2079
|
+
effectiveDate: SourceBackedValueSchema.optional(),
|
|
2080
|
+
expirationDate: SourceBackedValueSchema.optional(),
|
|
2081
|
+
retroactiveDate: SourceBackedValueSchema.optional(),
|
|
2082
|
+
premium: SourceBackedValueSchema.optional(),
|
|
2083
|
+
coverageTypes: z20.array(z20.string()).default([]),
|
|
2084
|
+
coverages: z20.array(OperationalCoverageLineSchema).default([]),
|
|
2085
|
+
parties: z20.array(OperationalPartySchema).default([]),
|
|
2086
|
+
endorsementSupport: z20.array(OperationalEndorsementSupportSchema).default([]),
|
|
2087
|
+
sourceNodeIds: z20.array(z20.string().min(1)).default([]),
|
|
2088
|
+
sourceSpanIds: z20.array(z20.string().min(1)).default([]),
|
|
2089
|
+
warnings: z20.array(z20.string()).default([])
|
|
2090
|
+
});
|
|
2009
2091
|
|
|
2010
2092
|
// src/source/ids.ts
|
|
2011
2093
|
function normalizeText(text) {
|
|
@@ -2189,8 +2271,8 @@ function chunkSourceSpans(spans, options = {}) {
|
|
|
2189
2271
|
if (current.length === 0) return;
|
|
2190
2272
|
const text = current.map((span) => span.text).join("\n\n");
|
|
2191
2273
|
const textHash = sourceSpanTextHash(text);
|
|
2192
|
-
const
|
|
2193
|
-
const
|
|
2274
|
+
const pageStart2 = firstNumber(current.map((span) => span.pageStart));
|
|
2275
|
+
const pageEnd2 = lastNumber(current.map((span) => span.pageEnd ?? span.pageStart));
|
|
2194
2276
|
const chunk = {
|
|
2195
2277
|
id: `${sanitizeIdPart(current[0].documentId)}:source_chunk:${chunks.length}:${stableHash2({
|
|
2196
2278
|
sourceSpanIds: current.map((span) => span.id),
|
|
@@ -2200,8 +2282,8 @@ function chunkSourceSpans(spans, options = {}) {
|
|
|
2200
2282
|
sourceSpanIds: current.map((span) => span.id),
|
|
2201
2283
|
text,
|
|
2202
2284
|
textHash,
|
|
2203
|
-
pageStart,
|
|
2204
|
-
pageEnd,
|
|
2285
|
+
pageStart: pageStart2,
|
|
2286
|
+
pageEnd: pageEnd2,
|
|
2205
2287
|
metadata: mergeMetadata(current)
|
|
2206
2288
|
};
|
|
2207
2289
|
chunks.push(SourceChunkSchema.parse(chunk));
|
|
@@ -2354,6 +2436,542 @@ function matchesFilters(span, filters) {
|
|
|
2354
2436
|
return true;
|
|
2355
2437
|
}
|
|
2356
2438
|
|
|
2439
|
+
// src/source/tree.ts
|
|
2440
|
+
function normalizeWhitespace2(value) {
|
|
2441
|
+
return value.replace(/\s+/g, " ").trim();
|
|
2442
|
+
}
|
|
2443
|
+
function sanitizeIdPart2(value) {
|
|
2444
|
+
return value.replace(/[^a-zA-Z0-9_.:-]/g, "_");
|
|
2445
|
+
}
|
|
2446
|
+
function truncate(value, maxChars) {
|
|
2447
|
+
const text = normalizeWhitespace2(value);
|
|
2448
|
+
return text.length > maxChars ? `${text.slice(0, maxChars).trimEnd()}...` : text;
|
|
2449
|
+
}
|
|
2450
|
+
function pageStart(span) {
|
|
2451
|
+
return span.pageStart ?? span.location?.page ?? span.location?.startPage;
|
|
2452
|
+
}
|
|
2453
|
+
function pageEnd(span) {
|
|
2454
|
+
return span.pageEnd ?? span.location?.endPage ?? pageStart(span);
|
|
2455
|
+
}
|
|
2456
|
+
function sourceUnit2(span) {
|
|
2457
|
+
return span.sourceUnit ?? span.metadata?.sourceUnit ?? span.metadata?.elementType;
|
|
2458
|
+
}
|
|
2459
|
+
function elementType(span) {
|
|
2460
|
+
return span.metadata?.elementType ?? span.metadata?.sourceUnit ?? span.sourceUnit;
|
|
2461
|
+
}
|
|
2462
|
+
function tableId(span) {
|
|
2463
|
+
return span.table?.tableId ?? span.metadata?.tableId;
|
|
2464
|
+
}
|
|
2465
|
+
function rowSpanId(span) {
|
|
2466
|
+
return span.parentSpanId ?? span.table?.rowSpanId ?? span.metadata?.rowSpanId;
|
|
2467
|
+
}
|
|
2468
|
+
function nodeId(documentId, kind, parts) {
|
|
2469
|
+
return [
|
|
2470
|
+
sanitizeIdPart2(documentId),
|
|
2471
|
+
"source_node",
|
|
2472
|
+
kind,
|
|
2473
|
+
stableHash2(parts.filter((part) => part !== void 0).join("|")).slice(0, 12)
|
|
2474
|
+
].join(":");
|
|
2475
|
+
}
|
|
2476
|
+
function titleCase(value) {
|
|
2477
|
+
return value.replace(/[_-]+/g, " ").replace(/\b\w/g, (char) => char.toUpperCase()).trim();
|
|
2478
|
+
}
|
|
2479
|
+
function nodeTextDescription(params) {
|
|
2480
|
+
return [
|
|
2481
|
+
params.title,
|
|
2482
|
+
params.kind.replace(/_/g, " "),
|
|
2483
|
+
params.page ? `page ${params.page}` : void 0,
|
|
2484
|
+
params.formNumber ? `form ${params.formNumber}` : void 0,
|
|
2485
|
+
params.text ? truncate(params.text, 1200) : void 0
|
|
2486
|
+
].filter(Boolean).join(" | ");
|
|
2487
|
+
}
|
|
2488
|
+
function normalizeNodeKind(span) {
|
|
2489
|
+
const unit = sourceUnit2(span);
|
|
2490
|
+
const element = elementType(span);
|
|
2491
|
+
if (unit === "page") return "page";
|
|
2492
|
+
if (unit === "table") return "table";
|
|
2493
|
+
if (unit === "table_row") return "table_row";
|
|
2494
|
+
if (unit === "table_cell") return "table_cell";
|
|
2495
|
+
if (unit === "key_value") return "schedule";
|
|
2496
|
+
if (unit === "section") return "section";
|
|
2497
|
+
if (element === "title" || element === "section_candidate") {
|
|
2498
|
+
const text = span.text.toLowerCase();
|
|
2499
|
+
if (/endorsement/.test(text)) return "endorsement";
|
|
2500
|
+
if (/schedule|declarations?/.test(text)) return "schedule";
|
|
2501
|
+
if (/clause|condition|exclusion|definition/.test(text)) return "clause";
|
|
2502
|
+
return "section";
|
|
2503
|
+
}
|
|
2504
|
+
return "text";
|
|
2505
|
+
}
|
|
2506
|
+
function pageNodeTitle(page) {
|
|
2507
|
+
return `Page ${page}`;
|
|
2508
|
+
}
|
|
2509
|
+
function makeNode(params) {
|
|
2510
|
+
return {
|
|
2511
|
+
id: params.id,
|
|
2512
|
+
documentId: params.documentId,
|
|
2513
|
+
parentId: params.parentId,
|
|
2514
|
+
kind: params.kind,
|
|
2515
|
+
title: params.title,
|
|
2516
|
+
description: params.description ?? nodeTextDescription({
|
|
2517
|
+
kind: params.kind,
|
|
2518
|
+
title: params.title,
|
|
2519
|
+
text: params.textExcerpt,
|
|
2520
|
+
page: params.pageStart,
|
|
2521
|
+
formNumber: typeof params.metadata?.formNumber === "string" ? params.metadata.formNumber : void 0
|
|
2522
|
+
}),
|
|
2523
|
+
textExcerpt: params.textExcerpt,
|
|
2524
|
+
sourceSpanIds: params.sourceSpanIds ?? [],
|
|
2525
|
+
pageStart: params.pageStart,
|
|
2526
|
+
pageEnd: params.pageEnd,
|
|
2527
|
+
bbox: params.bbox,
|
|
2528
|
+
order: params.order,
|
|
2529
|
+
path: "",
|
|
2530
|
+
metadata: params.metadata
|
|
2531
|
+
};
|
|
2532
|
+
}
|
|
2533
|
+
function sortSpans(left, right) {
|
|
2534
|
+
const leftPage = pageStart(left) ?? 0;
|
|
2535
|
+
const rightPage = pageStart(right) ?? 0;
|
|
2536
|
+
if (leftPage !== rightPage) return leftPage - rightPage;
|
|
2537
|
+
const leftRow = left.table?.rowIndex ?? Number(left.metadata?.rowIndex ?? 0);
|
|
2538
|
+
const rightRow = right.table?.rowIndex ?? Number(right.metadata?.rowIndex ?? 0);
|
|
2539
|
+
if (leftRow !== rightRow) return leftRow - rightRow;
|
|
2540
|
+
const leftCol = left.table?.columnIndex ?? Number(left.metadata?.columnIndex ?? 0);
|
|
2541
|
+
const rightCol = right.table?.columnIndex ?? Number(right.metadata?.columnIndex ?? 0);
|
|
2542
|
+
if (leftCol !== rightCol) return leftCol - rightCol;
|
|
2543
|
+
return left.id.localeCompare(right.id);
|
|
2544
|
+
}
|
|
2545
|
+
function normalizeDocumentSourceTreePaths(nodes) {
|
|
2546
|
+
const byParent = /* @__PURE__ */ new Map();
|
|
2547
|
+
for (const node of nodes) {
|
|
2548
|
+
const key = node.parentId;
|
|
2549
|
+
const group = byParent.get(key) ?? [];
|
|
2550
|
+
group.push(node);
|
|
2551
|
+
byParent.set(key, group);
|
|
2552
|
+
}
|
|
2553
|
+
for (const group of byParent.values()) {
|
|
2554
|
+
group.sort((left, right) => left.order - right.order || left.id.localeCompare(right.id));
|
|
2555
|
+
}
|
|
2556
|
+
const result = [];
|
|
2557
|
+
const visit = (node, path) => {
|
|
2558
|
+
const next = { ...node, path };
|
|
2559
|
+
result.push(next);
|
|
2560
|
+
const children = byParent.get(node.id) ?? [];
|
|
2561
|
+
children.forEach((child, index) => visit(child, `${path}.${index + 1}`));
|
|
2562
|
+
};
|
|
2563
|
+
const roots = byParent.get(void 0) ?? [];
|
|
2564
|
+
roots.forEach((root, index) => visit(root, String(index + 1)));
|
|
2565
|
+
return result;
|
|
2566
|
+
}
|
|
2567
|
+
function buildDocumentSourceTree(sourceSpans, documentId) {
|
|
2568
|
+
const orderedSpans = [...sourceSpans].sort(sortSpans);
|
|
2569
|
+
const resolvedDocumentId = documentId ?? orderedSpans[0]?.documentId ?? "document";
|
|
2570
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
2571
|
+
let order = 0;
|
|
2572
|
+
const rootId = nodeId(resolvedDocumentId, "document", [resolvedDocumentId]);
|
|
2573
|
+
nodes.set(rootId, makeNode({
|
|
2574
|
+
id: rootId,
|
|
2575
|
+
documentId: resolvedDocumentId,
|
|
2576
|
+
kind: "document",
|
|
2577
|
+
title: "Document",
|
|
2578
|
+
description: "Document root for source-native policy hierarchy",
|
|
2579
|
+
sourceSpanIds: orderedSpans.map((span) => span.id).slice(0, 200),
|
|
2580
|
+
pageStart: orderedSpans.map(pageStart).find((value) => typeof value === "number"),
|
|
2581
|
+
pageEnd: [...orderedSpans].reverse().map(pageEnd).find((value) => typeof value === "number"),
|
|
2582
|
+
order: order++,
|
|
2583
|
+
metadata: { sourceTreeVersion: "v3" }
|
|
2584
|
+
}));
|
|
2585
|
+
const pageNodeIds = /* @__PURE__ */ new Map();
|
|
2586
|
+
const tableNodeIds = /* @__PURE__ */ new Map();
|
|
2587
|
+
const rowNodeIds = /* @__PURE__ */ new Map();
|
|
2588
|
+
const ensurePage = (page) => {
|
|
2589
|
+
const existing = pageNodeIds.get(page);
|
|
2590
|
+
if (existing) return existing;
|
|
2591
|
+
const id = nodeId(resolvedDocumentId, "page", [page]);
|
|
2592
|
+
const pageSpan = orderedSpans.find((span) => pageStart(span) === page && sourceUnit2(span) === "page");
|
|
2593
|
+
nodes.set(id, makeNode({
|
|
2594
|
+
id,
|
|
2595
|
+
documentId: resolvedDocumentId,
|
|
2596
|
+
parentId: rootId,
|
|
2597
|
+
kind: "page",
|
|
2598
|
+
title: pageNodeTitle(page),
|
|
2599
|
+
description: pageSpan ? nodeTextDescription({ kind: "page", title: pageNodeTitle(page), text: pageSpan.text, page }) : pageNodeTitle(page),
|
|
2600
|
+
textExcerpt: pageSpan ? truncate(pageSpan.text, 1600) : void 0,
|
|
2601
|
+
sourceSpanIds: pageSpan ? [pageSpan.id] : [],
|
|
2602
|
+
pageStart: page,
|
|
2603
|
+
pageEnd: page,
|
|
2604
|
+
bbox: pageSpan?.bbox,
|
|
2605
|
+
order: order++,
|
|
2606
|
+
metadata: { sourceUnit: "page" }
|
|
2607
|
+
}));
|
|
2608
|
+
pageNodeIds.set(page, id);
|
|
2609
|
+
return id;
|
|
2610
|
+
};
|
|
2611
|
+
const ensureTable = (span, pageParentId) => {
|
|
2612
|
+
const idSource = tableId(span) ?? `${span.documentId}:p${pageStart(span) ?? "na"}:table:${nodes.size}`;
|
|
2613
|
+
const existing = tableNodeIds.get(idSource);
|
|
2614
|
+
if (existing) return existing;
|
|
2615
|
+
const id = nodeId(resolvedDocumentId, "table", [idSource]);
|
|
2616
|
+
nodes.set(id, makeNode({
|
|
2617
|
+
id,
|
|
2618
|
+
documentId: resolvedDocumentId,
|
|
2619
|
+
parentId: pageParentId,
|
|
2620
|
+
kind: "table",
|
|
2621
|
+
title: `Table ${tableNodeIds.size + 1}`,
|
|
2622
|
+
description: `Table on page ${pageStart(span) ?? "unknown"} for source rows and cells`,
|
|
2623
|
+
sourceSpanIds: [],
|
|
2624
|
+
pageStart: pageStart(span),
|
|
2625
|
+
pageEnd: pageEnd(span),
|
|
2626
|
+
order: order++,
|
|
2627
|
+
metadata: { tableId: idSource, sourceUnit: "table" }
|
|
2628
|
+
}));
|
|
2629
|
+
tableNodeIds.set(idSource, id);
|
|
2630
|
+
return id;
|
|
2631
|
+
};
|
|
2632
|
+
const addStandaloneSpanNode = (span, parentId) => {
|
|
2633
|
+
const kind = normalizeNodeKind(span);
|
|
2634
|
+
if (kind === "page") return;
|
|
2635
|
+
const page = pageStart(span);
|
|
2636
|
+
const title = span.sectionId ?? span.formNumber ?? (kind === "table_cell" && span.table?.columnName ? String(span.table.columnName) : void 0) ?? titleCase(kind);
|
|
2637
|
+
const id = nodeId(resolvedDocumentId, kind, [span.id]);
|
|
2638
|
+
nodes.set(id, makeNode({
|
|
2639
|
+
id,
|
|
2640
|
+
documentId: resolvedDocumentId,
|
|
2641
|
+
parentId,
|
|
2642
|
+
kind,
|
|
2643
|
+
title,
|
|
2644
|
+
description: nodeTextDescription({ kind, title, text: span.text, page, formNumber: span.formNumber }),
|
|
2645
|
+
textExcerpt: truncate(span.text, 1600),
|
|
2646
|
+
sourceSpanIds: [span.id],
|
|
2647
|
+
pageStart: page,
|
|
2648
|
+
pageEnd: pageEnd(span),
|
|
2649
|
+
bbox: span.bbox,
|
|
2650
|
+
order: order++,
|
|
2651
|
+
metadata: {
|
|
2652
|
+
...span.metadata ?? {},
|
|
2653
|
+
formNumber: span.formNumber,
|
|
2654
|
+
sourceUnit: sourceUnit2(span)
|
|
2655
|
+
}
|
|
2656
|
+
}));
|
|
2657
|
+
};
|
|
2658
|
+
for (const span of orderedSpans) {
|
|
2659
|
+
const page = pageStart(span);
|
|
2660
|
+
const pageParentId = page ? ensurePage(page) : rootId;
|
|
2661
|
+
const kind = normalizeNodeKind(span);
|
|
2662
|
+
if (kind === "page") continue;
|
|
2663
|
+
if (kind === "table_row") {
|
|
2664
|
+
const tableParentId = ensureTable(span, pageParentId);
|
|
2665
|
+
const rowKey = span.id;
|
|
2666
|
+
const id = nodeId(resolvedDocumentId, "table_row", [span.id]);
|
|
2667
|
+
nodes.set(id, makeNode({
|
|
2668
|
+
id,
|
|
2669
|
+
documentId: resolvedDocumentId,
|
|
2670
|
+
parentId: tableParentId,
|
|
2671
|
+
kind,
|
|
2672
|
+
title: span.table?.isHeader ? "Header row" : `Row ${(span.table?.rowIndex ?? 0) + 1}`,
|
|
2673
|
+
description: nodeTextDescription({ kind, title: "Table row", text: span.text, page }),
|
|
2674
|
+
textExcerpt: truncate(span.text, 1600),
|
|
2675
|
+
sourceSpanIds: [span.id],
|
|
2676
|
+
pageStart: page,
|
|
2677
|
+
pageEnd: pageEnd(span),
|
|
2678
|
+
bbox: span.bbox,
|
|
2679
|
+
order: order++,
|
|
2680
|
+
metadata: {
|
|
2681
|
+
...span.metadata ?? {},
|
|
2682
|
+
...span.table ?? {},
|
|
2683
|
+
sourceUnit: "table_row"
|
|
2684
|
+
}
|
|
2685
|
+
}));
|
|
2686
|
+
rowNodeIds.set(rowKey, id);
|
|
2687
|
+
continue;
|
|
2688
|
+
}
|
|
2689
|
+
if (kind === "table_cell") {
|
|
2690
|
+
const tableParentId = ensureTable(span, pageParentId);
|
|
2691
|
+
const parentRowId2 = rowSpanId(span);
|
|
2692
|
+
const parentId = parentRowId2 ? rowNodeIds.get(parentRowId2) ?? tableParentId : tableParentId;
|
|
2693
|
+
addStandaloneSpanNode(span, parentId);
|
|
2694
|
+
continue;
|
|
2695
|
+
}
|
|
2696
|
+
addStandaloneSpanNode(span, pageParentId);
|
|
2697
|
+
}
|
|
2698
|
+
return normalizeDocumentSourceTreePaths([...nodes.values()]);
|
|
2699
|
+
}
|
|
2700
|
+
|
|
2701
|
+
// src/source/operational-profile.ts
|
|
2702
|
+
function normalizeWhitespace3(value) {
|
|
2703
|
+
return value.replace(/\s+/g, " ").trim();
|
|
2704
|
+
}
|
|
2705
|
+
function cleanValue(value) {
|
|
2706
|
+
if (!value) return void 0;
|
|
2707
|
+
return normalizeWhitespace3(value.replace(/^[\s:;#-]+|[\s;,.]+$/g, ""));
|
|
2708
|
+
}
|
|
2709
|
+
function moneyValue(value) {
|
|
2710
|
+
const clean = cleanValue(value);
|
|
2711
|
+
if (!clean) return void 0;
|
|
2712
|
+
if (/^\$/.test(clean)) return clean;
|
|
2713
|
+
if (/^\d{1,3}(?:,\d{3})*(?:\.\d{2})?$/.test(clean)) return `$${clean}`;
|
|
2714
|
+
return clean;
|
|
2715
|
+
}
|
|
2716
|
+
function nodeText(node) {
|
|
2717
|
+
return normalizeWhitespace3([
|
|
2718
|
+
node.title,
|
|
2719
|
+
node.description,
|
|
2720
|
+
node.textExcerpt
|
|
2721
|
+
].filter(Boolean).join(" "));
|
|
2722
|
+
}
|
|
2723
|
+
function valueFromNode(node, value, confidence = "medium") {
|
|
2724
|
+
return {
|
|
2725
|
+
value,
|
|
2726
|
+
confidence,
|
|
2727
|
+
sourceNodeIds: [node.id],
|
|
2728
|
+
sourceSpanIds: node.sourceSpanIds
|
|
2729
|
+
};
|
|
2730
|
+
}
|
|
2731
|
+
function firstMatch(nodes, patterns) {
|
|
2732
|
+
for (const node of nodes) {
|
|
2733
|
+
const text = nodeText(node);
|
|
2734
|
+
for (const pattern of patterns) {
|
|
2735
|
+
const match = text.match(pattern);
|
|
2736
|
+
const value = cleanValue(match?.[1]);
|
|
2737
|
+
if (value) return valueFromNode(node, value, "high");
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
return void 0;
|
|
2741
|
+
}
|
|
2742
|
+
function inferPolicyTypes(nodes) {
|
|
2743
|
+
const text = nodes.slice(0, 40).map(nodeText).join(" ").toLowerCase();
|
|
2744
|
+
const types = [];
|
|
2745
|
+
const add = (pattern, type) => {
|
|
2746
|
+
if (pattern.test(text) && !types.includes(type)) types.push(type);
|
|
2747
|
+
};
|
|
2748
|
+
add(/\b(cyber|network security|privacy liability|data breach)\b/i, "cyber");
|
|
2749
|
+
add(/\b(professional liability|errors?\s*&?\s*omissions|e&o)\b/i, "professional_liability");
|
|
2750
|
+
add(/\b(commercial general liability|general liability|cgl)\b/i, "general_liability");
|
|
2751
|
+
add(/\b(umbrella|excess liability)\b/i, "umbrella");
|
|
2752
|
+
add(/\b(workers'? compensation|employers'? liability)\b/i, "workers_comp");
|
|
2753
|
+
add(/\b(commercial auto|business auto|automobile liability)\b/i, "commercial_auto");
|
|
2754
|
+
add(/\b(commercial property|property coverage|building coverage)\b/i, "commercial_property");
|
|
2755
|
+
return types.length ? types : ["other"];
|
|
2756
|
+
}
|
|
2757
|
+
function inferDocumentType(nodes) {
|
|
2758
|
+
const text = nodes.slice(0, 25).map(nodeText).join(" ").toLowerCase();
|
|
2759
|
+
if (/\b(quote|proposal|quotation|indication)\b/.test(text) && !/\bpolicy number\b/.test(text)) {
|
|
2760
|
+
return "quote";
|
|
2761
|
+
}
|
|
2762
|
+
return "policy";
|
|
2763
|
+
}
|
|
2764
|
+
function coverageNameFromRow(text) {
|
|
2765
|
+
const labelled = text.match(/\b(?:coverage|coverage part|line)\s*:?\s*([^|;$]{3,80})/i)?.[1];
|
|
2766
|
+
if (labelled) return cleanValue(labelled);
|
|
2767
|
+
const parts = text.split(/\s+\|\s+| {2,}|\t/).map(cleanValue).filter(Boolean);
|
|
2768
|
+
const first = parts.find(
|
|
2769
|
+
(part) => !/^(limit|limits?|deductible|premium|amount|basis|rate|retroactive|aggregate|each occurrence)$/i.test(part) && !/^\$?[\d,]+/.test(part)
|
|
2770
|
+
);
|
|
2771
|
+
return cleanValue(first);
|
|
2772
|
+
}
|
|
2773
|
+
function limitFromText(text) {
|
|
2774
|
+
return moneyValue(
|
|
2775
|
+
text.match(/\b(?:limit|liability|aggregate|occurrence|claim)\s*:?\s*(\$?\d[\d,]*(?:\.\d{2})?|\$?\d[\d,]*\s*(?:each|per|aggregate)[^|;]*)/i)?.[1] ?? text.match(/(\$\s?\d[\d,]*(?:\.\d{2})?)(?=.*\b(limit|aggregate|occurrence|claim|liability)\b)/i)?.[1]
|
|
2776
|
+
);
|
|
2777
|
+
}
|
|
2778
|
+
function deductibleFromText(text) {
|
|
2779
|
+
return moneyValue(text.match(/\b(?:deductible|retention|sir)\s*:?\s*(\$?\d[\d,]*(?:\.\d{2})?)/i)?.[1]);
|
|
2780
|
+
}
|
|
2781
|
+
function premiumFromText(text) {
|
|
2782
|
+
return moneyValue(text.match(/\b(?:premium|total premium|total cost|amount due)\s*:?\s*(\$?\d[\d,]*(?:\.\d{2})?)/i)?.[1]);
|
|
2783
|
+
}
|
|
2784
|
+
function buildCoverages(nodes) {
|
|
2785
|
+
const rows = nodes.filter((node) => {
|
|
2786
|
+
const text = nodeText(node);
|
|
2787
|
+
return (node.kind === "table_row" || node.kind === "schedule" || node.kind === "text") && /\b(coverage|limit|deductible|aggregate|occurrence|liability|premium)\b/i.test(text);
|
|
2788
|
+
});
|
|
2789
|
+
const coverages = [];
|
|
2790
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2791
|
+
for (const row of rows) {
|
|
2792
|
+
const text = nodeText(row);
|
|
2793
|
+
const name = coverageNameFromRow(text);
|
|
2794
|
+
const limit = limitFromText(text);
|
|
2795
|
+
const deductible = deductibleFromText(text);
|
|
2796
|
+
const premium = premiumFromText(text);
|
|
2797
|
+
if (!name || !limit && !deductible && !premium) continue;
|
|
2798
|
+
const key = [name.toLowerCase(), limit, deductible, premium].join("|");
|
|
2799
|
+
if (seen.has(key)) continue;
|
|
2800
|
+
seen.add(key);
|
|
2801
|
+
coverages.push({
|
|
2802
|
+
name,
|
|
2803
|
+
limit,
|
|
2804
|
+
deductible,
|
|
2805
|
+
premium,
|
|
2806
|
+
formNumber: typeof row.metadata?.formNumber === "string" ? row.metadata.formNumber : void 0,
|
|
2807
|
+
sourceNodeIds: [row.id],
|
|
2808
|
+
sourceSpanIds: row.sourceSpanIds
|
|
2809
|
+
});
|
|
2810
|
+
if (coverages.length >= 60) break;
|
|
2811
|
+
}
|
|
2812
|
+
return coverages;
|
|
2813
|
+
}
|
|
2814
|
+
function buildParties(profile) {
|
|
2815
|
+
const parties = [];
|
|
2816
|
+
if (profile.namedInsured) {
|
|
2817
|
+
parties.push({
|
|
2818
|
+
role: "named_insured",
|
|
2819
|
+
name: profile.namedInsured.value,
|
|
2820
|
+
sourceNodeIds: profile.namedInsured.sourceNodeIds,
|
|
2821
|
+
sourceSpanIds: profile.namedInsured.sourceSpanIds
|
|
2822
|
+
});
|
|
2823
|
+
}
|
|
2824
|
+
if (profile.insurer) {
|
|
2825
|
+
parties.push({
|
|
2826
|
+
role: "insurer",
|
|
2827
|
+
name: profile.insurer.value,
|
|
2828
|
+
sourceNodeIds: profile.insurer.sourceNodeIds,
|
|
2829
|
+
sourceSpanIds: profile.insurer.sourceSpanIds
|
|
2830
|
+
});
|
|
2831
|
+
}
|
|
2832
|
+
if (profile.broker) {
|
|
2833
|
+
parties.push({
|
|
2834
|
+
role: "broker",
|
|
2835
|
+
name: profile.broker.value,
|
|
2836
|
+
sourceNodeIds: profile.broker.sourceNodeIds,
|
|
2837
|
+
sourceSpanIds: profile.broker.sourceSpanIds
|
|
2838
|
+
});
|
|
2839
|
+
}
|
|
2840
|
+
return parties;
|
|
2841
|
+
}
|
|
2842
|
+
function buildEndorsementSupport(nodes) {
|
|
2843
|
+
const support = [];
|
|
2844
|
+
for (const node of nodes) {
|
|
2845
|
+
const text = nodeText(node);
|
|
2846
|
+
const add = (kind, status) => {
|
|
2847
|
+
if (support.some((item) => item.kind === kind && item.status === status && item.sourceNodeIds.includes(node.id))) {
|
|
2848
|
+
return;
|
|
2849
|
+
}
|
|
2850
|
+
support.push({
|
|
2851
|
+
kind,
|
|
2852
|
+
status,
|
|
2853
|
+
summary: node.textExcerpt ?? node.description,
|
|
2854
|
+
sourceNodeIds: [node.id],
|
|
2855
|
+
sourceSpanIds: node.sourceSpanIds
|
|
2856
|
+
});
|
|
2857
|
+
};
|
|
2858
|
+
if (/additional insured/i.test(text)) add("additional_insured", /not included|requires endorsement|only by endorsement/i.test(text) ? "requires_review" : "supported");
|
|
2859
|
+
if (/waiver of subrogation|subrogation.*waived/i.test(text)) add("waiver_of_subrogation", /not included|requires endorsement|only by endorsement/i.test(text) ? "requires_review" : "supported");
|
|
2860
|
+
if (/primary.*non[-\s]?contributory|non[-\s]?contributory/i.test(text)) add("primary_non_contributory", /not included|requires endorsement|only by endorsement/i.test(text) ? "requires_review" : "supported");
|
|
2861
|
+
if (/loss payee|mortgagee/i.test(text)) add(/mortgagee/i.test(text) ? "mortgagee" : "loss_payee", "supported");
|
|
2862
|
+
if (support.length >= 20) break;
|
|
2863
|
+
}
|
|
2864
|
+
return support;
|
|
2865
|
+
}
|
|
2866
|
+
function buildDeterministicOperationalProfile(params) {
|
|
2867
|
+
const nodes = params.sourceTree.filter((node) => node.kind !== "document");
|
|
2868
|
+
const partial = {
|
|
2869
|
+
documentType: inferDocumentType(nodes),
|
|
2870
|
+
policyTypes: inferPolicyTypes(nodes),
|
|
2871
|
+
policyNumber: firstMatch(nodes, [
|
|
2872
|
+
/\bpolicy\s*(?:number|no\.?|#)\s*:?\s*([A-Z0-9][A-Z0-9-]{4,})/i,
|
|
2873
|
+
/\bpolicy\s*[:#]\s*([A-Z0-9][A-Z0-9-]{4,})/i
|
|
2874
|
+
]),
|
|
2875
|
+
namedInsured: firstMatch(nodes, [
|
|
2876
|
+
/\b(?:named insured|insured name|insured)\s*:?\s*(.+?)(?=\s+(?:coverage|policy number|insurer|carrier|premium|effective|expiration)\b|[|;\n]|$)/i,
|
|
2877
|
+
/\b(?:applicant|policyholder)\s*:?\s*(.+?)(?=\s+(?:coverage|policy number|insurer|carrier|premium|effective|expiration)\b|[|;\n]|$)/i
|
|
2878
|
+
]),
|
|
2879
|
+
insurer: firstMatch(nodes, [
|
|
2880
|
+
/\b(?:insurer|carrier|company|security)\s*:?\s*([^|;\n]{3,120})/i,
|
|
2881
|
+
/\bunderwritten by\s+([^|;\n]{3,120})/i
|
|
2882
|
+
]),
|
|
2883
|
+
broker: firstMatch(nodes, [
|
|
2884
|
+
/\b(?:broker|producer|agent)\s*:?\s*([^|;\n]{3,120})/i
|
|
2885
|
+
]),
|
|
2886
|
+
effectiveDate: firstMatch(nodes, [
|
|
2887
|
+
/\b(?:effective date|policy period from|from)\s*:?\s*([0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4})/i,
|
|
2888
|
+
/\b([0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4})\s+(?:to|through|-)\s+[0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4}/i
|
|
2889
|
+
]),
|
|
2890
|
+
expirationDate: firstMatch(nodes, [
|
|
2891
|
+
/\b(?:expiration date|expiry date|expires|to)\s*:?\s*([0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4})/i,
|
|
2892
|
+
/\b[0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4}\s+(?:to|through|-)\s+([0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4})/i
|
|
2893
|
+
]),
|
|
2894
|
+
retroactiveDate: firstMatch(nodes, [
|
|
2895
|
+
/\bretroactive date\s*:?\s*([0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4}|full prior acts|none)/i
|
|
2896
|
+
]),
|
|
2897
|
+
premium: firstMatch(nodes, [
|
|
2898
|
+
/\b(?:total premium|premium|total cost|amount due)\s*:?\s*(\$?\d[\d,]*(?:\.\d{2})?)/i
|
|
2899
|
+
])
|
|
2900
|
+
};
|
|
2901
|
+
const coverages = buildCoverages(nodes);
|
|
2902
|
+
const coverageTypes = [...new Set(coverages.map((coverage) => coverage.name))];
|
|
2903
|
+
const sourceNodeIds = [.../* @__PURE__ */ new Set([
|
|
2904
|
+
...Object.values(partial).flatMap(
|
|
2905
|
+
(value) => value && typeof value === "object" && "sourceNodeIds" in value ? value.sourceNodeIds : []
|
|
2906
|
+
),
|
|
2907
|
+
...coverages.flatMap((coverage) => coverage.sourceNodeIds)
|
|
2908
|
+
])];
|
|
2909
|
+
const sourceSpanIds = [.../* @__PURE__ */ new Set([
|
|
2910
|
+
...Object.values(partial).flatMap(
|
|
2911
|
+
(value) => value && typeof value === "object" && "sourceSpanIds" in value ? value.sourceSpanIds : []
|
|
2912
|
+
),
|
|
2913
|
+
...coverages.flatMap((coverage) => coverage.sourceSpanIds)
|
|
2914
|
+
])];
|
|
2915
|
+
return PolicyOperationalProfileSchema.parse({
|
|
2916
|
+
...partial,
|
|
2917
|
+
coverageTypes,
|
|
2918
|
+
coverages,
|
|
2919
|
+
parties: buildParties(partial),
|
|
2920
|
+
endorsementSupport: buildEndorsementSupport(nodes),
|
|
2921
|
+
sourceNodeIds,
|
|
2922
|
+
sourceSpanIds,
|
|
2923
|
+
warnings: [
|
|
2924
|
+
...coverages.length === 0 ? ["No source-backed coverage schedule rows were identified deterministically."] : [],
|
|
2925
|
+
...!partial.policyNumber ? ["No source-backed policy number was identified deterministically."] : [],
|
|
2926
|
+
...!partial.namedInsured ? ["No source-backed named insured was identified deterministically."] : []
|
|
2927
|
+
]
|
|
2928
|
+
});
|
|
2929
|
+
}
|
|
2930
|
+
function mergeOperationalProfile(base, candidate, validNodeIds, validSpanIds) {
|
|
2931
|
+
const keepIds = (ids, valid) => Array.isArray(ids) ? ids.filter((id) => typeof id === "string" && valid.has(id)) : [];
|
|
2932
|
+
const mergeValue = (fallback, next) => {
|
|
2933
|
+
if (!next || typeof next !== "object" || Array.isArray(next)) return fallback;
|
|
2934
|
+
const record = next;
|
|
2935
|
+
const value = typeof record.value === "string" ? cleanValue(record.value) : void 0;
|
|
2936
|
+
if (!value) return fallback;
|
|
2937
|
+
const sourceNodeIds = keepIds(record.sourceNodeIds, validNodeIds);
|
|
2938
|
+
const sourceSpanIds = keepIds(record.sourceSpanIds, validSpanIds);
|
|
2939
|
+
if (sourceNodeIds.length === 0 && sourceSpanIds.length === 0) return fallback;
|
|
2940
|
+
return {
|
|
2941
|
+
value,
|
|
2942
|
+
normalizedValue: typeof record.normalizedValue === "string" ? record.normalizedValue : fallback?.normalizedValue,
|
|
2943
|
+
confidence: record.confidence === "high" || record.confidence === "low" || record.confidence === "medium" ? record.confidence : "medium",
|
|
2944
|
+
sourceNodeIds,
|
|
2945
|
+
sourceSpanIds
|
|
2946
|
+
};
|
|
2947
|
+
};
|
|
2948
|
+
const coverages = Array.isArray(candidate.coverages) ? candidate.coverages.map((coverage) => ({
|
|
2949
|
+
...coverage,
|
|
2950
|
+
sourceNodeIds: keepIds(coverage.sourceNodeIds, validNodeIds),
|
|
2951
|
+
sourceSpanIds: keepIds(coverage.sourceSpanIds, validSpanIds)
|
|
2952
|
+
})).filter((coverage) => coverage.name && (coverage.sourceNodeIds.length > 0 || coverage.sourceSpanIds.length > 0)) : base.coverages;
|
|
2953
|
+
return PolicyOperationalProfileSchema.parse({
|
|
2954
|
+
...base,
|
|
2955
|
+
documentType: candidate.documentType === "quote" ? "quote" : candidate.documentType === "policy" ? "policy" : base.documentType,
|
|
2956
|
+
policyTypes: Array.isArray(candidate.policyTypes) && candidate.policyTypes.length > 0 ? candidate.policyTypes : base.policyTypes,
|
|
2957
|
+
policyNumber: mergeValue(base.policyNumber, candidate.policyNumber),
|
|
2958
|
+
namedInsured: mergeValue(base.namedInsured, candidate.namedInsured),
|
|
2959
|
+
insurer: mergeValue(base.insurer, candidate.insurer),
|
|
2960
|
+
broker: mergeValue(base.broker, candidate.broker),
|
|
2961
|
+
effectiveDate: mergeValue(base.effectiveDate, candidate.effectiveDate),
|
|
2962
|
+
expirationDate: mergeValue(base.expirationDate, candidate.expirationDate),
|
|
2963
|
+
retroactiveDate: mergeValue(base.retroactiveDate, candidate.retroactiveDate),
|
|
2964
|
+
premium: mergeValue(base.premium, candidate.premium),
|
|
2965
|
+
coverageTypes: Array.isArray(candidate.coverageTypes) && candidate.coverageTypes.length > 0 ? candidate.coverageTypes : base.coverageTypes,
|
|
2966
|
+
coverages,
|
|
2967
|
+
parties: base.parties,
|
|
2968
|
+
endorsementSupport: base.endorsementSupport,
|
|
2969
|
+
sourceNodeIds: [.../* @__PURE__ */ new Set([...base.sourceNodeIds, ...keepIds(candidate.sourceNodeIds, validNodeIds)])],
|
|
2970
|
+
sourceSpanIds: [.../* @__PURE__ */ new Set([...base.sourceSpanIds, ...keepIds(candidate.sourceSpanIds, validSpanIds)])],
|
|
2971
|
+
warnings: base.warnings
|
|
2972
|
+
});
|
|
2973
|
+
}
|
|
2974
|
+
|
|
2357
2975
|
// src/extraction/pdf.ts
|
|
2358
2976
|
import {
|
|
2359
2977
|
PDFDocument,
|
|
@@ -2743,15 +3361,15 @@ function normalizeItem(ref, item) {
|
|
|
2743
3361
|
if (!text) return void 0;
|
|
2744
3362
|
const table = getItemTable(item);
|
|
2745
3363
|
const pages = (item.prov ?? []).map((prov) => getPageNumber(prov)).filter((page) => typeof page === "number" && page > 0);
|
|
2746
|
-
const
|
|
2747
|
-
const
|
|
3364
|
+
const pageStart2 = pages.length ? Math.min(...pages) : void 0;
|
|
3365
|
+
const pageEnd2 = pages.length ? Math.max(...pages) : pageStart2;
|
|
2748
3366
|
const bboxes = (item.prov ?? []).map((prov) => toSourceSpanBBox(prov)).filter((bbox) => Boolean(bbox));
|
|
2749
3367
|
return {
|
|
2750
3368
|
ref,
|
|
2751
3369
|
label: typeof item.label === "string" ? item.label : void 0,
|
|
2752
3370
|
text,
|
|
2753
|
-
pageStart,
|
|
2754
|
-
pageEnd,
|
|
3371
|
+
pageStart: pageStart2,
|
|
3372
|
+
pageEnd: pageEnd2,
|
|
2755
3373
|
bboxes: bboxes.length ? bboxes : void 0,
|
|
2756
3374
|
table
|
|
2757
3375
|
};
|
|
@@ -2763,7 +3381,7 @@ function buildSourceSpansForUnit(unit, index, options) {
|
|
|
2763
3381
|
doclingRef: unit.ref,
|
|
2764
3382
|
...unit.label ? { doclingLabel: unit.label } : {}
|
|
2765
3383
|
};
|
|
2766
|
-
const
|
|
3384
|
+
const tableId2 = unit.table ? `${unit.ref}:table` : void 0;
|
|
2767
3385
|
const tableSpan = withDoclingKind(buildSourceSpan(
|
|
2768
3386
|
{
|
|
2769
3387
|
documentId: options.documentId,
|
|
@@ -2773,7 +3391,7 @@ function buildSourceSpansForUnit(unit, index, options) {
|
|
|
2773
3391
|
pageEnd: unit.pageEnd,
|
|
2774
3392
|
sectionId: unit.label,
|
|
2775
3393
|
sourceUnit: unit.table ? "table" : labelToSourceUnit(unit.label),
|
|
2776
|
-
table:
|
|
3394
|
+
table: tableId2 ? { tableId: tableId2 } : void 0,
|
|
2777
3395
|
metadata: baseMetadata
|
|
2778
3396
|
},
|
|
2779
3397
|
index * 1e3
|
|
@@ -2797,7 +3415,7 @@ function buildSourceSpansForUnit(unit, index, options) {
|
|
|
2797
3415
|
sourceUnit: "table_row",
|
|
2798
3416
|
parentSpanId: tableSpan.id,
|
|
2799
3417
|
table: {
|
|
2800
|
-
tableId,
|
|
3418
|
+
tableId: tableId2,
|
|
2801
3419
|
tableSpanId: tableSpan.id,
|
|
2802
3420
|
rowIndex,
|
|
2803
3421
|
isHeader
|
|
@@ -2805,7 +3423,7 @@ function buildSourceSpansForUnit(unit, index, options) {
|
|
|
2805
3423
|
metadata: {
|
|
2806
3424
|
...baseMetadata,
|
|
2807
3425
|
sourceUnit: "table_row",
|
|
2808
|
-
tableId:
|
|
3426
|
+
tableId: tableId2 ?? "",
|
|
2809
3427
|
tableSpanId: tableSpan.id,
|
|
2810
3428
|
rowIndex: String(rowIndex),
|
|
2811
3429
|
isHeader: String(isHeader)
|
|
@@ -2829,7 +3447,7 @@ function buildSourceSpansForUnit(unit, index, options) {
|
|
|
2829
3447
|
sourceUnit: "table_cell",
|
|
2830
3448
|
parentSpanId: rowSpan.id,
|
|
2831
3449
|
table: {
|
|
2832
|
-
tableId,
|
|
3450
|
+
tableId: tableId2,
|
|
2833
3451
|
tableSpanId: tableSpan.id,
|
|
2834
3452
|
rowSpanId: rowSpan.id,
|
|
2835
3453
|
rowIndex,
|
|
@@ -2840,7 +3458,7 @@ function buildSourceSpansForUnit(unit, index, options) {
|
|
|
2840
3458
|
metadata: {
|
|
2841
3459
|
...baseMetadata,
|
|
2842
3460
|
sourceUnit: "table_cell",
|
|
2843
|
-
tableId:
|
|
3461
|
+
tableId: tableId2 ?? "",
|
|
2844
3462
|
tableSpanId: tableSpan.id,
|
|
2845
3463
|
rowSpanId: rowSpan.id,
|
|
2846
3464
|
rowIndex: String(rowIndex),
|
|
@@ -2995,7 +3613,7 @@ function buildSourceContext(spans, maxChars = 12e3) {
|
|
|
2995
3613
|
const lines = [];
|
|
2996
3614
|
let length = 0;
|
|
2997
3615
|
for (const span of orderSourceSpansForContext(spans)) {
|
|
2998
|
-
const unit =
|
|
3616
|
+
const unit = sourceUnit3(span);
|
|
2999
3617
|
const table = span.table;
|
|
3000
3618
|
const tableContext = [
|
|
3001
3619
|
unit ? ` unit:${unit}` : "",
|
|
@@ -3019,11 +3637,11 @@ ${lines.join("\n\n")}
|
|
|
3019
3637
|
|
|
3020
3638
|
Use sourceSpan IDs when grounding extracted contractual values.`;
|
|
3021
3639
|
}
|
|
3022
|
-
function
|
|
3640
|
+
function sourceUnit3(span) {
|
|
3023
3641
|
return span.sourceUnit ?? span.metadata?.sourceUnit;
|
|
3024
3642
|
}
|
|
3025
3643
|
function sourceContextRank(span) {
|
|
3026
|
-
switch (
|
|
3644
|
+
switch (sourceUnit3(span)) {
|
|
3027
3645
|
case "table_row":
|
|
3028
3646
|
return 0;
|
|
3029
3647
|
case "table":
|
|
@@ -3042,10 +3660,10 @@ function sourceContextRank(span) {
|
|
|
3042
3660
|
}
|
|
3043
3661
|
function orderSourceSpansForContext(spans) {
|
|
3044
3662
|
const parentRows = new Set(
|
|
3045
|
-
spans.filter((span) =>
|
|
3663
|
+
spans.filter((span) => sourceUnit3(span) === "table_row").map((span) => span.id)
|
|
3046
3664
|
);
|
|
3047
3665
|
const filtered = spans.filter((span) => {
|
|
3048
|
-
if (
|
|
3666
|
+
if (sourceUnit3(span) !== "table_cell") return true;
|
|
3049
3667
|
const parent = span.parentSpanId ?? span.table?.rowSpanId ?? span.metadata?.rowSpanId;
|
|
3050
3668
|
return !parent || !parentRows.has(parent);
|
|
3051
3669
|
});
|
|
@@ -3439,7 +4057,7 @@ function stringValue2(record, ...keys) {
|
|
|
3439
4057
|
function stringArray(value) {
|
|
3440
4058
|
return Array.isArray(value) ? value.filter((item) => typeof item === "string" && item.length > 0) : [];
|
|
3441
4059
|
}
|
|
3442
|
-
function
|
|
4060
|
+
function sourceUnit4(span) {
|
|
3443
4061
|
return span.sourceUnit ?? span.metadata?.sourceUnit;
|
|
3444
4062
|
}
|
|
3445
4063
|
function spanPage(span) {
|
|
@@ -3449,7 +4067,7 @@ function spanPageEnd(span) {
|
|
|
3449
4067
|
return span.pageEnd ?? span.location?.endPage ?? spanPage(span);
|
|
3450
4068
|
}
|
|
3451
4069
|
function sourceSpansForPage(sourceSpans, page) {
|
|
3452
|
-
return sourceSpans.filter((span) => spanPage(span) === page &&
|
|
4070
|
+
return sourceSpans.filter((span) => spanPage(span) === page && sourceUnit4(span) === "page").map((span) => span.id);
|
|
3453
4071
|
}
|
|
3454
4072
|
function nodePageOverlaps(node, record) {
|
|
3455
4073
|
const recordStart = numberValue(record, "pageNumber", "pageStart", "resolvedFromPage");
|
|
@@ -3501,8 +4119,8 @@ function attachDocumentNodeIds(document, nodes) {
|
|
|
3501
4119
|
function buildNodeFromSection(section, index) {
|
|
3502
4120
|
const title = stringValue2(section, "title", "name", "sectionRef") ?? `Section ${index + 1}`;
|
|
3503
4121
|
const id = stringValue2(section, "documentNodeId", "recordId") ?? `section:${index}:${slugPart(title)}`;
|
|
3504
|
-
const
|
|
3505
|
-
const
|
|
4122
|
+
const pageStart2 = numberValue(section, "pageStart", "pageNumber");
|
|
4123
|
+
const pageEnd2 = numberValue(section, "pageEnd", "pageNumber") ?? pageStart2;
|
|
3506
4124
|
const type = stringValue2(section, "type");
|
|
3507
4125
|
const coverageType = stringValue2(section, "coverageType");
|
|
3508
4126
|
const sourceSpanIds = stringArray(section.sourceSpanIds);
|
|
@@ -3517,8 +4135,8 @@ function buildNodeFromSection(section, index) {
|
|
|
3517
4135
|
label: type,
|
|
3518
4136
|
level: 2,
|
|
3519
4137
|
sectionNumber: stringValue2(subsection, "sectionNumber"),
|
|
3520
|
-
pageStart: numberValue(subsection, "pageNumber") ??
|
|
3521
|
-
pageEnd: numberValue(subsection, "pageNumber") ??
|
|
4138
|
+
pageStart: numberValue(subsection, "pageNumber") ?? pageStart2,
|
|
4139
|
+
pageEnd: numberValue(subsection, "pageNumber") ?? pageStart2,
|
|
3522
4140
|
excerpt: stringValue2(subsection, "excerpt"),
|
|
3523
4141
|
content: stringValue2(subsection, "content"),
|
|
3524
4142
|
sourceSpanIds: stringArray(subsection.sourceSpanIds),
|
|
@@ -3533,8 +4151,8 @@ function buildNodeFromSection(section, index) {
|
|
|
3533
4151
|
label: type,
|
|
3534
4152
|
level: 1,
|
|
3535
4153
|
sectionNumber: stringValue2(section, "sectionNumber"),
|
|
3536
|
-
pageStart,
|
|
3537
|
-
pageEnd,
|
|
4154
|
+
pageStart: pageStart2,
|
|
4155
|
+
pageEnd: pageEnd2,
|
|
3538
4156
|
formNumber: stringValue2(section, "formNumber"),
|
|
3539
4157
|
formTitle: stringValue2(section, "formTitle"),
|
|
3540
4158
|
excerpt: stringValue2(section, "excerpt"),
|
|
@@ -3547,17 +4165,17 @@ function buildNodeFromSection(section, index) {
|
|
|
3547
4165
|
}
|
|
3548
4166
|
function buildNodesFromSourceSpans(sourceSpans) {
|
|
3549
4167
|
const candidates = sourceSpans.filter((span) => {
|
|
3550
|
-
const unit =
|
|
4168
|
+
const unit = sourceUnit4(span);
|
|
3551
4169
|
return unit === "section" || unit === "section_candidate" || unit === "page";
|
|
3552
4170
|
});
|
|
3553
4171
|
return candidates.sort((left, right) => (spanPage(left) ?? 0) - (spanPage(right) ?? 0) || left.id.localeCompare(right.id)).map((span, index) => {
|
|
3554
|
-
const title = span.sectionId ?? span.formNumber ?? (
|
|
4172
|
+
const title = span.sectionId ?? span.formNumber ?? (sourceUnit4(span) === "page" && spanPage(span) ? `Page ${spanPage(span)}` : `Source unit ${index + 1}`);
|
|
3555
4173
|
return {
|
|
3556
4174
|
id: `source:${index}:${slugPart(span.id)}`,
|
|
3557
4175
|
title,
|
|
3558
4176
|
originalTitle: title,
|
|
3559
|
-
type:
|
|
3560
|
-
label:
|
|
4177
|
+
type: sourceUnit4(span),
|
|
4178
|
+
label: sourceUnit4(span),
|
|
3561
4179
|
level: 1,
|
|
3562
4180
|
pageStart: spanPage(span),
|
|
3563
4181
|
pageEnd: spanPageEnd(span),
|
|
@@ -7309,7 +7927,7 @@ function numberValue2(value) {
|
|
|
7309
7927
|
function normalize(value) {
|
|
7310
7928
|
return value.toLowerCase().replace(/&/g, "and").replace(/[^a-z0-9]+/g, " ").trim();
|
|
7311
7929
|
}
|
|
7312
|
-
function
|
|
7930
|
+
function sourceUnit5(span) {
|
|
7313
7931
|
return span.sourceUnit ?? span.metadata?.sourceUnit;
|
|
7314
7932
|
}
|
|
7315
7933
|
function pageNumber(span) {
|
|
@@ -7379,7 +7997,7 @@ function firstField(fields, patterns) {
|
|
|
7379
7997
|
}
|
|
7380
7998
|
function coverageFromRow(span) {
|
|
7381
7999
|
const rowText = span.text.trim();
|
|
7382
|
-
if (!rowText ||
|
|
8000
|
+
if (!rowText || sourceUnit5(span) !== "table_row") return void 0;
|
|
7383
8001
|
if (span.table?.isHeader || span.metadata?.isHeader === "true") return void 0;
|
|
7384
8002
|
const fields = splitRowFields(rowText);
|
|
7385
8003
|
let name;
|
|
@@ -7459,7 +8077,7 @@ function recoverCoverageScheduleRows(params) {
|
|
|
7459
8077
|
const payload = params.memory.get("coverage_limits");
|
|
7460
8078
|
const existing = Array.isArray(payload?.coverages) ? payload.coverages : [];
|
|
7461
8079
|
const pages = coveragePages(params.pageAssignments);
|
|
7462
|
-
const candidates = params.sourceSpans.filter((span) =>
|
|
8080
|
+
const candidates = params.sourceSpans.filter((span) => sourceUnit5(span) === "table_row").filter((span) => {
|
|
7463
8081
|
const page = pageNumber(span);
|
|
7464
8082
|
return page !== void 0 && pages.has(page);
|
|
7465
8083
|
}).map(coverageFromRow).filter((coverage) => Boolean(coverage));
|
|
@@ -8095,13 +8713,13 @@ function buildPlanFromPageAssignments(pageAssignments, pageCount, formInventory)
|
|
|
8095
8713
|
const expanded = new Set(pages);
|
|
8096
8714
|
for (const page of pages) {
|
|
8097
8715
|
for (const form of contextualForms) {
|
|
8098
|
-
const
|
|
8099
|
-
const
|
|
8716
|
+
const pageStart2 = form.pageStart;
|
|
8717
|
+
const pageEnd2 = form.pageEnd ?? form.pageStart;
|
|
8100
8718
|
const formType = form.formType;
|
|
8101
8719
|
const supportsContextualExpansion = extractorName === "endorsements" ? formType === "endorsement" : formType === "coverage" || formType === "endorsement";
|
|
8102
8720
|
if (!supportsContextualExpansion) continue;
|
|
8103
|
-
if (page <
|
|
8104
|
-
for (let current =
|
|
8721
|
+
if (page < pageStart2 || page > pageEnd2) continue;
|
|
8722
|
+
for (let current = pageStart2; current <= pageEnd2; current += 1) {
|
|
8105
8723
|
expanded.add(current);
|
|
8106
8724
|
}
|
|
8107
8725
|
}
|
|
@@ -8182,11 +8800,11 @@ function textMatches(record, span) {
|
|
|
8182
8800
|
function sourceHashFor(spans) {
|
|
8183
8801
|
return spans.map((span) => span.textHash ?? span.hash).filter(Boolean).join(":") || void 0;
|
|
8184
8802
|
}
|
|
8185
|
-
function
|
|
8803
|
+
function sourceUnit6(span) {
|
|
8186
8804
|
return span.sourceUnit ?? span.metadata?.sourceUnit;
|
|
8187
8805
|
}
|
|
8188
8806
|
function hierarchyScore(span) {
|
|
8189
|
-
switch (
|
|
8807
|
+
switch (sourceUnit6(span)) {
|
|
8190
8808
|
case "table_row":
|
|
8191
8809
|
return 5;
|
|
8192
8810
|
case "table":
|
|
@@ -8209,8 +8827,8 @@ function preferParentRows(matches, sourceSpans) {
|
|
|
8209
8827
|
const expanded = [];
|
|
8210
8828
|
const seen = /* @__PURE__ */ new Set();
|
|
8211
8829
|
for (const match of matches) {
|
|
8212
|
-
const parent =
|
|
8213
|
-
const preferred = parent &&
|
|
8830
|
+
const parent = sourceUnit6(match) === "table_cell" ? byId.get(parentRowId(match) ?? "") : void 0;
|
|
8831
|
+
const preferred = parent && sourceUnit6(parent) === "table_row" ? parent : match;
|
|
8214
8832
|
if (seen.has(preferred.id)) continue;
|
|
8215
8833
|
seen.add(preferred.id);
|
|
8216
8834
|
expanded.push(preferred);
|
|
@@ -8219,11 +8837,11 @@ function preferParentRows(matches, sourceSpans) {
|
|
|
8219
8837
|
}
|
|
8220
8838
|
function findSourceSpansForRecord(record, sourceSpans) {
|
|
8221
8839
|
if (sourceSpans.length === 0) return [];
|
|
8222
|
-
const
|
|
8223
|
-
const
|
|
8840
|
+
const pageStart2 = numberValue3(record, "pageNumber", "pageStart");
|
|
8841
|
+
const pageEnd2 = numberValue3(record, "pageNumber", "pageEnd");
|
|
8224
8842
|
const scored = sourceSpans.map((span) => {
|
|
8225
8843
|
let score = 0;
|
|
8226
|
-
if (pageOverlaps(
|
|
8844
|
+
if (pageOverlaps(pageStart2, pageEnd2, span)) score += 4;
|
|
8227
8845
|
if (formMatches(record, span)) score += 3;
|
|
8228
8846
|
if (textMatches(record, span)) score += 2;
|
|
8229
8847
|
if (score > 0) score += hierarchyScore(span);
|
|
@@ -8262,6 +8880,422 @@ function groundExtractionMemoryWithSourceSpans(memory, sourceSpans) {
|
|
|
8262
8880
|
}
|
|
8263
8881
|
}
|
|
8264
8882
|
|
|
8883
|
+
// src/extraction/source-tree-extractor.ts
|
|
8884
|
+
import { z as z41 } from "zod";
|
|
8885
|
+
var ORGANIZABLE_KINDS = [
|
|
8886
|
+
"page_group",
|
|
8887
|
+
"form",
|
|
8888
|
+
"endorsement",
|
|
8889
|
+
"section",
|
|
8890
|
+
"schedule",
|
|
8891
|
+
"clause"
|
|
8892
|
+
];
|
|
8893
|
+
var SourceTreeOrganizationSchema = z41.object({
|
|
8894
|
+
labels: z41.array(z41.object({
|
|
8895
|
+
nodeId: z41.string(),
|
|
8896
|
+
kind: z41.enum([
|
|
8897
|
+
"document",
|
|
8898
|
+
"page_group",
|
|
8899
|
+
"page",
|
|
8900
|
+
"form",
|
|
8901
|
+
"endorsement",
|
|
8902
|
+
"section",
|
|
8903
|
+
"schedule",
|
|
8904
|
+
"clause",
|
|
8905
|
+
"table",
|
|
8906
|
+
"table_row",
|
|
8907
|
+
"table_cell",
|
|
8908
|
+
"text"
|
|
8909
|
+
]).optional(),
|
|
8910
|
+
title: z41.string().optional(),
|
|
8911
|
+
description: z41.string().optional()
|
|
8912
|
+
})).default([]),
|
|
8913
|
+
groups: z41.array(z41.object({
|
|
8914
|
+
kind: z41.enum(ORGANIZABLE_KINDS),
|
|
8915
|
+
title: z41.string(),
|
|
8916
|
+
description: z41.string().optional(),
|
|
8917
|
+
childNodeIds: z41.array(z41.string()).min(1)
|
|
8918
|
+
})).default([])
|
|
8919
|
+
});
|
|
8920
|
+
var SourceBackedValueForPromptSchema = z41.object({
|
|
8921
|
+
value: z41.string(),
|
|
8922
|
+
normalizedValue: z41.string().optional(),
|
|
8923
|
+
confidence: z41.enum(["low", "medium", "high"]).optional(),
|
|
8924
|
+
sourceNodeIds: z41.array(z41.string()).default([]),
|
|
8925
|
+
sourceSpanIds: z41.array(z41.string()).default([])
|
|
8926
|
+
});
|
|
8927
|
+
var OperationalProfilePromptSchema = z41.object({
|
|
8928
|
+
documentType: z41.enum(["policy", "quote"]).optional(),
|
|
8929
|
+
policyTypes: z41.array(z41.string()).optional(),
|
|
8930
|
+
policyNumber: SourceBackedValueForPromptSchema.optional(),
|
|
8931
|
+
namedInsured: SourceBackedValueForPromptSchema.optional(),
|
|
8932
|
+
insurer: SourceBackedValueForPromptSchema.optional(),
|
|
8933
|
+
broker: SourceBackedValueForPromptSchema.optional(),
|
|
8934
|
+
effectiveDate: SourceBackedValueForPromptSchema.optional(),
|
|
8935
|
+
expirationDate: SourceBackedValueForPromptSchema.optional(),
|
|
8936
|
+
retroactiveDate: SourceBackedValueForPromptSchema.optional(),
|
|
8937
|
+
premium: SourceBackedValueForPromptSchema.optional(),
|
|
8938
|
+
coverageTypes: z41.array(z41.string()).optional(),
|
|
8939
|
+
coverages: z41.array(z41.object({
|
|
8940
|
+
name: z41.string(),
|
|
8941
|
+
coverageCode: z41.string().optional(),
|
|
8942
|
+
limit: z41.string().optional(),
|
|
8943
|
+
deductible: z41.string().optional(),
|
|
8944
|
+
premium: z41.string().optional(),
|
|
8945
|
+
formNumber: z41.string().optional(),
|
|
8946
|
+
sectionRef: z41.string().optional(),
|
|
8947
|
+
sourceNodeIds: z41.array(z41.string()).default([]),
|
|
8948
|
+
sourceSpanIds: z41.array(z41.string()).default([])
|
|
8949
|
+
})).optional(),
|
|
8950
|
+
sourceNodeIds: z41.array(z41.string()).optional(),
|
|
8951
|
+
sourceSpanIds: z41.array(z41.string()).optional()
|
|
8952
|
+
});
|
|
8953
|
+
function cleanText(value, fallback) {
|
|
8954
|
+
const text = value?.replace(/\s+/g, " ").trim();
|
|
8955
|
+
return text || fallback;
|
|
8956
|
+
}
|
|
8957
|
+
function compactNode(node) {
|
|
8958
|
+
return {
|
|
8959
|
+
id: node.id,
|
|
8960
|
+
kind: node.kind,
|
|
8961
|
+
title: node.title,
|
|
8962
|
+
path: node.path,
|
|
8963
|
+
pageStart: node.pageStart,
|
|
8964
|
+
pageEnd: node.pageEnd,
|
|
8965
|
+
sourceSpanIds: node.sourceSpanIds.slice(0, 8),
|
|
8966
|
+
text: (node.textExcerpt ?? node.description).slice(0, 700)
|
|
8967
|
+
};
|
|
8968
|
+
}
|
|
8969
|
+
function buildOrganizationPrompt(sourceTree) {
|
|
8970
|
+
const nodes = sourceTree.filter((node) => node.kind !== "table_cell").slice(0, 180).map(compactNode);
|
|
8971
|
+
return `You organize an insurance document source tree.
|
|
8972
|
+
|
|
8973
|
+
Rules:
|
|
8974
|
+
- Use only node IDs from the provided list.
|
|
8975
|
+
- Do not invent text, page numbers, source spans, limits, or policy facts.
|
|
8976
|
+
- You may relabel existing nodes and group adjacent top-level/page nodes when they are clearly one form, endorsement, declarations set, schedule, or clause family.
|
|
8977
|
+
- Groups must list existing childNodeIds only.
|
|
8978
|
+
- Keep descriptions short and useful for search.
|
|
8979
|
+
|
|
8980
|
+
Source nodes:
|
|
8981
|
+
${JSON.stringify(nodes, null, 2)}
|
|
8982
|
+
|
|
8983
|
+
Return JSON with labels and groups only.`;
|
|
8984
|
+
}
|
|
8985
|
+
function buildOperationalProfilePrompt(sourceTree, fallback) {
|
|
8986
|
+
const nodes = sourceTree.filter((node) => node.kind !== "document").slice(0, 240).map(compactNode);
|
|
8987
|
+
return `Extract a source-backed operational profile for an insurance policy or quote.
|
|
8988
|
+
|
|
8989
|
+
Return only high-value operational facts needed for policy lists, Q&A, compliance, and certificate generation:
|
|
8990
|
+
- policy number, named insured, insurer/carrier/security, broker/producer, policy period, retroactive date, premium
|
|
8991
|
+
- coverage lines with limits, deductibles, premiums, and form references
|
|
8992
|
+
- coverage type labels
|
|
8993
|
+
|
|
8994
|
+
Rules:
|
|
8995
|
+
- Every returned value must include sourceNodeIds or sourceSpanIds from the provided nodes.
|
|
8996
|
+
- If a value is not directly supported, omit it.
|
|
8997
|
+
- Prefer declarations, schedules, premium tables, and endorsement schedules over generic policy wording.
|
|
8998
|
+
- Do not copy entire policy wording into fields.
|
|
8999
|
+
|
|
9000
|
+
Deterministic baseline:
|
|
9001
|
+
${JSON.stringify(fallback, null, 2)}
|
|
9002
|
+
|
|
9003
|
+
Source nodes:
|
|
9004
|
+
${JSON.stringify(nodes, null, 2)}
|
|
9005
|
+
|
|
9006
|
+
Return JSON for the operational profile.`;
|
|
9007
|
+
}
|
|
9008
|
+
function groupNodeId(documentId, group) {
|
|
9009
|
+
return [
|
|
9010
|
+
documentId.replace(/[^a-zA-Z0-9_.:-]/g, "_"),
|
|
9011
|
+
"source_node",
|
|
9012
|
+
group.kind,
|
|
9013
|
+
group.childNodeIds.join("_").replace(/[^a-zA-Z0-9_.:-]/g, "_").slice(0, 80)
|
|
9014
|
+
].join(":");
|
|
9015
|
+
}
|
|
9016
|
+
function applyOrganization(sourceTree, organization) {
|
|
9017
|
+
const byId = new Map(sourceTree.map((node) => [node.id, node]));
|
|
9018
|
+
let nextTree = sourceTree.map((node) => {
|
|
9019
|
+
const label = organization.labels.find((item) => item.nodeId === node.id);
|
|
9020
|
+
if (!label) return node;
|
|
9021
|
+
return {
|
|
9022
|
+
...node,
|
|
9023
|
+
kind: label.kind ?? node.kind,
|
|
9024
|
+
title: cleanText(label.title, node.title),
|
|
9025
|
+
description: cleanText(label.description, node.description)
|
|
9026
|
+
};
|
|
9027
|
+
});
|
|
9028
|
+
for (const group of organization.groups.slice(0, 40)) {
|
|
9029
|
+
const children = group.childNodeIds.map((id2) => byId.get(id2)).filter((node2) => Boolean(node2));
|
|
9030
|
+
if (children.length === 0) continue;
|
|
9031
|
+
const parentId = children[0].parentId;
|
|
9032
|
+
if (!children.every((child) => child.parentId === parentId)) continue;
|
|
9033
|
+
const documentId = children[0].documentId;
|
|
9034
|
+
const id = groupNodeId(documentId, group);
|
|
9035
|
+
if (byId.has(id)) continue;
|
|
9036
|
+
const sourceSpanIds = [...new Set(children.flatMap((child) => child.sourceSpanIds))];
|
|
9037
|
+
const pageStarts = children.map((child) => child.pageStart).filter((page) => typeof page === "number");
|
|
9038
|
+
const pageEnds = children.map((child) => child.pageEnd ?? child.pageStart).filter((page) => typeof page === "number");
|
|
9039
|
+
const order = Math.min(...children.map((child) => child.order));
|
|
9040
|
+
const node = {
|
|
9041
|
+
id,
|
|
9042
|
+
documentId,
|
|
9043
|
+
parentId,
|
|
9044
|
+
kind: group.kind,
|
|
9045
|
+
title: group.title,
|
|
9046
|
+
description: group.description ?? group.title,
|
|
9047
|
+
textExcerpt: children.map((child) => child.textExcerpt ?? child.description).filter(Boolean).join("\n\n").slice(0, 1600),
|
|
9048
|
+
sourceSpanIds,
|
|
9049
|
+
pageStart: pageStarts.length ? Math.min(...pageStarts) : void 0,
|
|
9050
|
+
pageEnd: pageEnds.length ? Math.max(...pageEnds) : void 0,
|
|
9051
|
+
bbox: children.flatMap((child) => child.bbox ?? []).slice(0, 12),
|
|
9052
|
+
order,
|
|
9053
|
+
path: "",
|
|
9054
|
+
metadata: { sourceTreeVersion: "v3", organizer: "llm_group" }
|
|
9055
|
+
};
|
|
9056
|
+
nextTree = [
|
|
9057
|
+
...nextTree.map(
|
|
9058
|
+
(child) => group.childNodeIds.includes(child.id) ? { ...child, parentId: id, order: child.order + 1e-3 } : child
|
|
9059
|
+
),
|
|
9060
|
+
node
|
|
9061
|
+
];
|
|
9062
|
+
byId.set(id, node);
|
|
9063
|
+
}
|
|
9064
|
+
return normalizeDocumentSourceTreePaths(nextTree);
|
|
9065
|
+
}
|
|
9066
|
+
function sourceTreeToOutline(sourceTree) {
|
|
9067
|
+
const byParent = /* @__PURE__ */ new Map();
|
|
9068
|
+
for (const node of sourceTree.filter((item) => item.kind !== "document")) {
|
|
9069
|
+
const group = byParent.get(node.parentId) ?? [];
|
|
9070
|
+
group.push(node);
|
|
9071
|
+
byParent.set(node.parentId, group);
|
|
9072
|
+
}
|
|
9073
|
+
const root = sourceTree.find((node) => node.kind === "document");
|
|
9074
|
+
const visit = (node) => ({
|
|
9075
|
+
id: node.id,
|
|
9076
|
+
title: node.title,
|
|
9077
|
+
type: node.kind,
|
|
9078
|
+
label: node.kind,
|
|
9079
|
+
pageStart: node.pageStart,
|
|
9080
|
+
pageEnd: node.pageEnd,
|
|
9081
|
+
excerpt: node.textExcerpt,
|
|
9082
|
+
content: node.textExcerpt,
|
|
9083
|
+
sourceSpanIds: node.sourceSpanIds,
|
|
9084
|
+
sourceTextHash: node.sourceSpanIds.join(":") || void 0,
|
|
9085
|
+
interpretationLabels: [node.kind],
|
|
9086
|
+
children: (byParent.get(node.id) ?? []).map(visit)
|
|
9087
|
+
});
|
|
9088
|
+
return (byParent.get(root?.id) ?? []).map(visit);
|
|
9089
|
+
}
|
|
9090
|
+
function valueOf(profile, key) {
|
|
9091
|
+
const value = profile[key];
|
|
9092
|
+
return value && typeof value === "object" && !Array.isArray(value) && "value" in value ? String(value.value) : void 0;
|
|
9093
|
+
}
|
|
9094
|
+
function materializeDocument(params) {
|
|
9095
|
+
const profile = params.operationalProfile;
|
|
9096
|
+
const policyNumber = valueOf(profile, "policyNumber") ?? "Unknown";
|
|
9097
|
+
const insuredName = valueOf(profile, "namedInsured") ?? "Unknown";
|
|
9098
|
+
const carrier = valueOf(profile, "insurer") ?? "Unknown";
|
|
9099
|
+
const effectiveDate = valueOf(profile, "effectiveDate") ?? "Unknown";
|
|
9100
|
+
const expirationDate = valueOf(profile, "expirationDate") ?? "Unknown";
|
|
9101
|
+
const premium = valueOf(profile, "premium");
|
|
9102
|
+
const coverages = profile.coverages.map((coverage) => ({
|
|
9103
|
+
name: coverage.name,
|
|
9104
|
+
coverageCode: coverage.coverageCode,
|
|
9105
|
+
limit: coverage.limit,
|
|
9106
|
+
deductible: coverage.deductible,
|
|
9107
|
+
premium: coverage.premium,
|
|
9108
|
+
formNumber: coverage.formNumber,
|
|
9109
|
+
sectionRef: coverage.sectionRef,
|
|
9110
|
+
sourceSpanIds: coverage.sourceSpanIds,
|
|
9111
|
+
documentNodeId: coverage.sourceNodeIds[0],
|
|
9112
|
+
originalContent: [coverage.name, coverage.limit, coverage.deductible, coverage.premium].filter(Boolean).join(" | ")
|
|
9113
|
+
}));
|
|
9114
|
+
const documentOutline = sourceTreeToOutline(params.sourceTree);
|
|
9115
|
+
const documentMetadata = {
|
|
9116
|
+
sourceTreeVersion: "v3",
|
|
9117
|
+
sourceTreeCanonical: true,
|
|
9118
|
+
tableOfContents: documentOutline.map((node) => ({
|
|
9119
|
+
title: node.title,
|
|
9120
|
+
pageStart: node.pageStart,
|
|
9121
|
+
pageEnd: node.pageEnd,
|
|
9122
|
+
documentNodeId: node.id,
|
|
9123
|
+
sourceSpanIds: node.sourceSpanIds
|
|
9124
|
+
})),
|
|
9125
|
+
agentGuidance: [
|
|
9126
|
+
{
|
|
9127
|
+
kind: "source_tree",
|
|
9128
|
+
title: "Use the source tree as canonical evidence",
|
|
9129
|
+
detail: "Operational fields are projections from source nodes and source spans. Use source nodes for policy wording and exact provenance."
|
|
9130
|
+
}
|
|
9131
|
+
]
|
|
9132
|
+
};
|
|
9133
|
+
const summary = [
|
|
9134
|
+
carrier !== "Unknown" ? carrier : void 0,
|
|
9135
|
+
policyNumber !== "Unknown" ? `#${policyNumber}` : void 0,
|
|
9136
|
+
insuredName !== "Unknown" ? `for ${insuredName}` : void 0,
|
|
9137
|
+
profile.coverageTypes.length ? `covering ${profile.coverageTypes.slice(0, 5).join(", ")}` : void 0
|
|
9138
|
+
].filter(Boolean).join(" ");
|
|
9139
|
+
const base = {
|
|
9140
|
+
id: params.id,
|
|
9141
|
+
type: profile.documentType,
|
|
9142
|
+
carrier,
|
|
9143
|
+
security: carrier,
|
|
9144
|
+
insuredName,
|
|
9145
|
+
premium,
|
|
9146
|
+
policyTypes: profile.policyTypes,
|
|
9147
|
+
coverages,
|
|
9148
|
+
documentMetadata,
|
|
9149
|
+
documentOutline,
|
|
9150
|
+
declarations: {
|
|
9151
|
+
fields: [
|
|
9152
|
+
profile.policyNumber ? { field: "policyNumber", value: profile.policyNumber.value, sourceSpanIds: profile.policyNumber.sourceSpanIds } : void 0,
|
|
9153
|
+
profile.namedInsured ? { field: "namedInsured", value: profile.namedInsured.value, sourceSpanIds: profile.namedInsured.sourceSpanIds } : void 0,
|
|
9154
|
+
profile.insurer ? { field: "insurer", value: profile.insurer.value, sourceSpanIds: profile.insurer.sourceSpanIds } : void 0,
|
|
9155
|
+
profile.effectiveDate ? { field: "policyPeriodStart", value: profile.effectiveDate.value, sourceSpanIds: profile.effectiveDate.sourceSpanIds } : void 0,
|
|
9156
|
+
profile.expirationDate ? { field: "policyPeriodEnd", value: profile.expirationDate.value, sourceSpanIds: profile.expirationDate.sourceSpanIds } : void 0
|
|
9157
|
+
].filter(Boolean)
|
|
9158
|
+
},
|
|
9159
|
+
supplementaryFacts: profile.endorsementSupport.map((item) => ({
|
|
9160
|
+
key: item.kind,
|
|
9161
|
+
value: item.summary,
|
|
9162
|
+
sourceSpanIds: item.sourceSpanIds,
|
|
9163
|
+
documentNodeId: item.sourceNodeIds[0]
|
|
9164
|
+
})),
|
|
9165
|
+
summary: summary || void 0
|
|
9166
|
+
};
|
|
9167
|
+
if (profile.documentType === "quote") {
|
|
9168
|
+
return {
|
|
9169
|
+
...base,
|
|
9170
|
+
type: "quote",
|
|
9171
|
+
quoteNumber: policyNumber,
|
|
9172
|
+
proposedEffectiveDate: effectiveDate === "Unknown" ? void 0 : effectiveDate,
|
|
9173
|
+
proposedExpirationDate: expirationDate === "Unknown" ? void 0 : expirationDate
|
|
9174
|
+
};
|
|
9175
|
+
}
|
|
9176
|
+
return {
|
|
9177
|
+
...base,
|
|
9178
|
+
type: "policy",
|
|
9179
|
+
policyNumber,
|
|
9180
|
+
effectiveDate,
|
|
9181
|
+
expirationDate,
|
|
9182
|
+
retroactiveDate: valueOf(profile, "retroactiveDate")
|
|
9183
|
+
};
|
|
9184
|
+
}
|
|
9185
|
+
async function runSourceTreeExtraction(params) {
|
|
9186
|
+
let sourceTree = buildDocumentSourceTree(params.sourceSpans, params.id);
|
|
9187
|
+
const warnings = [];
|
|
9188
|
+
let modelCalls = 0;
|
|
9189
|
+
let callsWithUsage = 0;
|
|
9190
|
+
let callsMissingUsage = 0;
|
|
9191
|
+
const tokenUsage = { inputTokens: 0, outputTokens: 0 };
|
|
9192
|
+
const performanceReport = { modelCalls: [], totalModelCallDurationMs: 0 };
|
|
9193
|
+
const localTrack = (usage, report) => {
|
|
9194
|
+
modelCalls += 1;
|
|
9195
|
+
if (usage) {
|
|
9196
|
+
callsWithUsage += 1;
|
|
9197
|
+
tokenUsage.inputTokens += usage.inputTokens;
|
|
9198
|
+
tokenUsage.outputTokens += usage.outputTokens;
|
|
9199
|
+
} else {
|
|
9200
|
+
callsMissingUsage += 1;
|
|
9201
|
+
}
|
|
9202
|
+
if (report) {
|
|
9203
|
+
performanceReport.modelCalls.push({ ...report, usage, usageReported: !!usage });
|
|
9204
|
+
if (report.durationMs != null) performanceReport.totalModelCallDurationMs += report.durationMs;
|
|
9205
|
+
}
|
|
9206
|
+
params.trackUsage(usage, report);
|
|
9207
|
+
};
|
|
9208
|
+
try {
|
|
9209
|
+
const budget = params.resolveBudget("extraction_source_tree", 4096);
|
|
9210
|
+
const startedAt = Date.now();
|
|
9211
|
+
const response = await safeGenerateObject(
|
|
9212
|
+
params.generateObject,
|
|
9213
|
+
{
|
|
9214
|
+
prompt: buildOrganizationPrompt(sourceTree),
|
|
9215
|
+
schema: SourceTreeOrganizationSchema,
|
|
9216
|
+
maxTokens: budget.maxTokens,
|
|
9217
|
+
taskKind: "extraction_source_tree",
|
|
9218
|
+
budgetDiagnostics: budget,
|
|
9219
|
+
providerOptions: { ...params.providerOptions, sourceSpans: params.sourceSpans }
|
|
9220
|
+
},
|
|
9221
|
+
{
|
|
9222
|
+
fallback: { labels: [], groups: [] },
|
|
9223
|
+
log: params.log
|
|
9224
|
+
}
|
|
9225
|
+
);
|
|
9226
|
+
localTrack(response.usage, {
|
|
9227
|
+
taskKind: "extraction_source_tree",
|
|
9228
|
+
label: "source_tree_organizer",
|
|
9229
|
+
maxTokens: budget.maxTokens,
|
|
9230
|
+
durationMs: Date.now() - startedAt
|
|
9231
|
+
});
|
|
9232
|
+
sourceTree = applyOrganization(sourceTree, response.object);
|
|
9233
|
+
} catch (error) {
|
|
9234
|
+
warnings.push(`Source-tree organizer failed; deterministic tree used (${error instanceof Error ? error.message : String(error)})`);
|
|
9235
|
+
}
|
|
9236
|
+
const deterministicProfile = buildDeterministicOperationalProfile({
|
|
9237
|
+
sourceTree,
|
|
9238
|
+
sourceSpans: params.sourceSpans
|
|
9239
|
+
});
|
|
9240
|
+
let operationalProfile = deterministicProfile;
|
|
9241
|
+
try {
|
|
9242
|
+
const validNodeIds = new Set(sourceTree.map((node) => node.id));
|
|
9243
|
+
const validSpanIds = new Set(params.sourceSpans.map((span) => span.id));
|
|
9244
|
+
const budget = params.resolveBudget("extraction_operational_profile", 8192);
|
|
9245
|
+
const startedAt = Date.now();
|
|
9246
|
+
const response = await safeGenerateObject(
|
|
9247
|
+
params.generateObject,
|
|
9248
|
+
{
|
|
9249
|
+
prompt: buildOperationalProfilePrompt(sourceTree, deterministicProfile),
|
|
9250
|
+
schema: OperationalProfilePromptSchema,
|
|
9251
|
+
maxTokens: budget.maxTokens,
|
|
9252
|
+
taskKind: "extraction_operational_profile",
|
|
9253
|
+
budgetDiagnostics: budget,
|
|
9254
|
+
providerOptions: { ...params.providerOptions, sourceSpans: params.sourceSpans, sourceTree }
|
|
9255
|
+
},
|
|
9256
|
+
{
|
|
9257
|
+
fallback: deterministicProfile,
|
|
9258
|
+
log: params.log
|
|
9259
|
+
}
|
|
9260
|
+
);
|
|
9261
|
+
localTrack(response.usage, {
|
|
9262
|
+
taskKind: "extraction_operational_profile",
|
|
9263
|
+
label: "operational_profile",
|
|
9264
|
+
maxTokens: budget.maxTokens,
|
|
9265
|
+
durationMs: Date.now() - startedAt
|
|
9266
|
+
});
|
|
9267
|
+
operationalProfile = mergeOperationalProfile(
|
|
9268
|
+
deterministicProfile,
|
|
9269
|
+
response.object,
|
|
9270
|
+
validNodeIds,
|
|
9271
|
+
validSpanIds
|
|
9272
|
+
);
|
|
9273
|
+
} catch (error) {
|
|
9274
|
+
warnings.push(`Operational profile model pass failed; deterministic profile used (${error instanceof Error ? error.message : String(error)})`);
|
|
9275
|
+
}
|
|
9276
|
+
const document = materializeDocument({
|
|
9277
|
+
id: params.id,
|
|
9278
|
+
sourceTree,
|
|
9279
|
+
operationalProfile
|
|
9280
|
+
});
|
|
9281
|
+
return {
|
|
9282
|
+
sourceTree,
|
|
9283
|
+
sourceSpans: params.sourceSpans,
|
|
9284
|
+
sourceChunks: chunkSourceSpans(params.sourceSpans),
|
|
9285
|
+
operationalProfile,
|
|
9286
|
+
document,
|
|
9287
|
+
chunks: [],
|
|
9288
|
+
warnings: [...warnings, ...operationalProfile.warnings],
|
|
9289
|
+
tokenUsage,
|
|
9290
|
+
usageReporting: {
|
|
9291
|
+
modelCalls,
|
|
9292
|
+
callsWithUsage,
|
|
9293
|
+
callsMissingUsage
|
|
9294
|
+
},
|
|
9295
|
+
performanceReport
|
|
9296
|
+
};
|
|
9297
|
+
}
|
|
9298
|
+
|
|
8265
9299
|
// src/extraction/coordinator.ts
|
|
8266
9300
|
function createExtractor(config) {
|
|
8267
9301
|
const {
|
|
@@ -8447,17 +9481,17 @@ ${span.text}` : span.text;
|
|
|
8447
9481
|
const candidateSpans = spansForPageRange(spans, startPage, endPage).filter((span) => span.text.trim().length > 0).filter((span) => span.metadata?.sourceUnit === "section_candidate" || span.sectionId || span.text.length >= 160);
|
|
8448
9482
|
return {
|
|
8449
9483
|
sections: candidateSpans.map((span, index) => {
|
|
8450
|
-
const
|
|
8451
|
-
const
|
|
8452
|
-
const title = span.sectionId ?? span.formNumber ?? firstHeadingLine(span.text) ?? `Policy text page ${
|
|
9484
|
+
const pageStart2 = span.pageStart ?? span.location?.startPage ?? span.location?.page ?? startPage;
|
|
9485
|
+
const pageEnd2 = span.pageEnd ?? span.location?.endPage ?? pageStart2;
|
|
9486
|
+
const title = span.sectionId ?? span.formNumber ?? firstHeadingLine(span.text) ?? `Policy text page ${pageStart2}`;
|
|
8453
9487
|
return {
|
|
8454
9488
|
title,
|
|
8455
9489
|
sectionNumber: span.formNumber,
|
|
8456
|
-
pageStart,
|
|
8457
|
-
pageEnd,
|
|
9490
|
+
pageStart: pageStart2,
|
|
9491
|
+
pageEnd: pageEnd2,
|
|
8458
9492
|
type: inferSectionType(title, span.text),
|
|
8459
9493
|
excerpt: span.text.slice(0, 240),
|
|
8460
|
-
recordId: `section_index_${
|
|
9494
|
+
recordId: `section_index_${pageStart2}_${index}`,
|
|
8461
9495
|
sourceSpanIds: [span.id],
|
|
8462
9496
|
sourceTextHash: span.textHash ?? sourceSpanTextHash(span.text)
|
|
8463
9497
|
};
|
|
@@ -8596,6 +9630,51 @@ ${span.text}` : span.text;
|
|
|
8596
9630
|
await sourceStore.addSourceChunks(sourceChunks);
|
|
8597
9631
|
}
|
|
8598
9632
|
}
|
|
9633
|
+
if (sourceSpans.length > 0) {
|
|
9634
|
+
onProgress?.("Building source-native document tree...");
|
|
9635
|
+
const v3 = await runSourceTreeExtraction({
|
|
9636
|
+
id,
|
|
9637
|
+
sourceSpans,
|
|
9638
|
+
generateObject,
|
|
9639
|
+
providerOptions: activeProviderOptions,
|
|
9640
|
+
resolveBudget,
|
|
9641
|
+
trackUsage,
|
|
9642
|
+
log
|
|
9643
|
+
});
|
|
9644
|
+
const reviewReport2 = {
|
|
9645
|
+
issues: v3.warnings.map((warning) => ({
|
|
9646
|
+
code: "source_tree_warning",
|
|
9647
|
+
severity: "warning",
|
|
9648
|
+
message: warning
|
|
9649
|
+
})),
|
|
9650
|
+
rounds: [],
|
|
9651
|
+
artifacts: [
|
|
9652
|
+
{ kind: "source_tree", label: "Source Tree", itemCount: v3.sourceTree.length },
|
|
9653
|
+
{ kind: "source_spans", label: "Source Spans", itemCount: v3.sourceSpans.length },
|
|
9654
|
+
{ kind: "operational_profile", label: "Operational Profile", itemCount: v3.operationalProfile.coverages.length }
|
|
9655
|
+
],
|
|
9656
|
+
reviewRoundRecords: [],
|
|
9657
|
+
formInventory: [],
|
|
9658
|
+
qualityGateStatus: v3.warnings.length > 0 ? "warning" : "passed"
|
|
9659
|
+
};
|
|
9660
|
+
if (shouldFailQualityGate(qualityGate, reviewReport2.qualityGateStatus)) {
|
|
9661
|
+
throw new Error("Extraction quality gate failed. See reviewReport for blocking issues.");
|
|
9662
|
+
}
|
|
9663
|
+
onProgress?.("Source-tree extraction complete.");
|
|
9664
|
+
return {
|
|
9665
|
+
document: v3.document,
|
|
9666
|
+
chunks: [],
|
|
9667
|
+
sourceSpans: v3.sourceSpans,
|
|
9668
|
+
sourceChunks: v3.sourceChunks,
|
|
9669
|
+
sourceTree: v3.sourceTree,
|
|
9670
|
+
operationalProfile: v3.operationalProfile,
|
|
9671
|
+
warnings: v3.warnings,
|
|
9672
|
+
tokenUsage: v3.tokenUsage,
|
|
9673
|
+
usageReporting: v3.usageReporting,
|
|
9674
|
+
performanceReport: v3.performanceReport,
|
|
9675
|
+
reviewReport: reviewReport2
|
|
9676
|
+
};
|
|
9677
|
+
}
|
|
8599
9678
|
const pipelineCtx = createPipelineContext({
|
|
8600
9679
|
id,
|
|
8601
9680
|
onSave: onCheckpointSave,
|
|
@@ -9466,8 +10545,8 @@ Respond with JSON only:
|
|
|
9466
10545
|
}`;
|
|
9467
10546
|
|
|
9468
10547
|
// src/schemas/application.ts
|
|
9469
|
-
import { z as
|
|
9470
|
-
var FieldTypeSchema =
|
|
10548
|
+
import { z as z42 } from "zod";
|
|
10549
|
+
var FieldTypeSchema = z42.enum([
|
|
9471
10550
|
"text",
|
|
9472
10551
|
"numeric",
|
|
9473
10552
|
"currency",
|
|
@@ -9476,138 +10555,138 @@ var FieldTypeSchema = z41.enum([
|
|
|
9476
10555
|
"table",
|
|
9477
10556
|
"declaration"
|
|
9478
10557
|
]);
|
|
9479
|
-
var ApplicationFieldSchema =
|
|
9480
|
-
id:
|
|
9481
|
-
label:
|
|
9482
|
-
section:
|
|
10558
|
+
var ApplicationFieldSchema = z42.object({
|
|
10559
|
+
id: z42.string(),
|
|
10560
|
+
label: z42.string(),
|
|
10561
|
+
section: z42.string(),
|
|
9483
10562
|
fieldType: FieldTypeSchema,
|
|
9484
|
-
required:
|
|
9485
|
-
options:
|
|
9486
|
-
columns:
|
|
9487
|
-
requiresExplanationIfYes:
|
|
9488
|
-
condition:
|
|
9489
|
-
dependsOn:
|
|
9490
|
-
whenValue:
|
|
10563
|
+
required: z42.boolean(),
|
|
10564
|
+
options: z42.array(z42.string()).optional(),
|
|
10565
|
+
columns: z42.array(z42.string()).optional(),
|
|
10566
|
+
requiresExplanationIfYes: z42.boolean().optional(),
|
|
10567
|
+
condition: z42.object({
|
|
10568
|
+
dependsOn: z42.string(),
|
|
10569
|
+
whenValue: z42.string()
|
|
9491
10570
|
}).optional(),
|
|
9492
|
-
value:
|
|
9493
|
-
source:
|
|
9494
|
-
confidence:
|
|
9495
|
-
sourceSpanIds:
|
|
9496
|
-
userSourceSpanIds:
|
|
9497
|
-
pageNumber:
|
|
9498
|
-
fieldAnchorId:
|
|
9499
|
-
acroFormName:
|
|
9500
|
-
validationStatus:
|
|
9501
|
-
});
|
|
9502
|
-
var ApplicationClassifyResultSchema =
|
|
9503
|
-
isApplication:
|
|
9504
|
-
confidence:
|
|
9505
|
-
applicationType:
|
|
9506
|
-
});
|
|
9507
|
-
var FieldExtractionResultSchema =
|
|
9508
|
-
fields:
|
|
9509
|
-
});
|
|
9510
|
-
var AutoFillMatchSchema =
|
|
9511
|
-
fieldId:
|
|
9512
|
-
value:
|
|
9513
|
-
confidence:
|
|
9514
|
-
contextKey:
|
|
9515
|
-
});
|
|
9516
|
-
var AutoFillResultSchema =
|
|
9517
|
-
matches:
|
|
9518
|
-
});
|
|
9519
|
-
var QuestionBatchResultSchema =
|
|
9520
|
-
batches:
|
|
9521
|
-
});
|
|
9522
|
-
var LookupRequestSchema =
|
|
9523
|
-
type:
|
|
9524
|
-
description:
|
|
9525
|
-
url:
|
|
9526
|
-
targetFieldIds:
|
|
9527
|
-
});
|
|
9528
|
-
var ReplyIntentSchema =
|
|
9529
|
-
primaryIntent:
|
|
9530
|
-
hasAnswers:
|
|
9531
|
-
questionText:
|
|
9532
|
-
questionFieldIds:
|
|
9533
|
-
lookupRequests:
|
|
9534
|
-
});
|
|
9535
|
-
var ParsedAnswerSchema =
|
|
9536
|
-
fieldId:
|
|
9537
|
-
value:
|
|
9538
|
-
explanation:
|
|
9539
|
-
});
|
|
9540
|
-
var AnswerParsingResultSchema =
|
|
9541
|
-
answers:
|
|
9542
|
-
unanswered:
|
|
9543
|
-
});
|
|
9544
|
-
var LookupFillSchema =
|
|
9545
|
-
fieldId:
|
|
9546
|
-
value:
|
|
9547
|
-
source:
|
|
9548
|
-
sourceSpanIds:
|
|
9549
|
-
});
|
|
9550
|
-
var LookupFillResultSchema =
|
|
9551
|
-
fills:
|
|
9552
|
-
unfillable:
|
|
9553
|
-
explanation:
|
|
9554
|
-
});
|
|
9555
|
-
var FlatPdfPlacementSchema =
|
|
9556
|
-
fieldId:
|
|
9557
|
-
page:
|
|
9558
|
-
x:
|
|
9559
|
-
y:
|
|
9560
|
-
text:
|
|
9561
|
-
fontSize:
|
|
9562
|
-
isCheckmark:
|
|
9563
|
-
});
|
|
9564
|
-
var AcroFormMappingSchema =
|
|
9565
|
-
fieldId:
|
|
9566
|
-
acroFormName:
|
|
9567
|
-
value:
|
|
9568
|
-
});
|
|
9569
|
-
var QualityGateStatusSchema =
|
|
9570
|
-
var QualitySeveritySchema =
|
|
9571
|
-
var ApplicationQualityIssueSchema =
|
|
9572
|
-
code:
|
|
10571
|
+
value: z42.string().optional(),
|
|
10572
|
+
source: z42.string().optional().describe("Where the value came from: auto-fill, user, lookup"),
|
|
10573
|
+
confidence: z42.enum(["confirmed", "high", "medium", "low"]).optional(),
|
|
10574
|
+
sourceSpanIds: z42.array(z42.string()).optional().describe("Stable source spans that support the field value or field anchor"),
|
|
10575
|
+
userSourceSpanIds: z42.array(z42.string()).optional().describe("Message or attachment spans that support user-provided values"),
|
|
10576
|
+
pageNumber: z42.number().int().positive().optional().describe("Application page where the field label or anchor appears"),
|
|
10577
|
+
fieldAnchorId: z42.string().optional().describe("Stable field anchor ID derived from page, section, label, and form metadata"),
|
|
10578
|
+
acroFormName: z42.string().optional().describe("Native PDF AcroForm field name when available"),
|
|
10579
|
+
validationStatus: z42.enum(["valid", "needs_review", "unsupported", "missing"]).optional()
|
|
10580
|
+
});
|
|
10581
|
+
var ApplicationClassifyResultSchema = z42.object({
|
|
10582
|
+
isApplication: z42.boolean(),
|
|
10583
|
+
confidence: z42.number().min(0).max(1),
|
|
10584
|
+
applicationType: z42.string().nullable()
|
|
10585
|
+
});
|
|
10586
|
+
var FieldExtractionResultSchema = z42.object({
|
|
10587
|
+
fields: z42.array(ApplicationFieldSchema)
|
|
10588
|
+
});
|
|
10589
|
+
var AutoFillMatchSchema = z42.object({
|
|
10590
|
+
fieldId: z42.string(),
|
|
10591
|
+
value: z42.string(),
|
|
10592
|
+
confidence: z42.enum(["confirmed"]),
|
|
10593
|
+
contextKey: z42.string()
|
|
10594
|
+
});
|
|
10595
|
+
var AutoFillResultSchema = z42.object({
|
|
10596
|
+
matches: z42.array(AutoFillMatchSchema)
|
|
10597
|
+
});
|
|
10598
|
+
var QuestionBatchResultSchema = z42.object({
|
|
10599
|
+
batches: z42.array(z42.array(z42.string()).describe("Array of field IDs in this batch"))
|
|
10600
|
+
});
|
|
10601
|
+
var LookupRequestSchema = z42.object({
|
|
10602
|
+
type: z42.string().describe("Type of lookup: 'records', 'website', 'policy'"),
|
|
10603
|
+
description: z42.string(),
|
|
10604
|
+
url: z42.string().optional(),
|
|
10605
|
+
targetFieldIds: z42.array(z42.string())
|
|
10606
|
+
});
|
|
10607
|
+
var ReplyIntentSchema = z42.object({
|
|
10608
|
+
primaryIntent: z42.enum(["answers_only", "question", "lookup_request", "mixed"]),
|
|
10609
|
+
hasAnswers: z42.boolean(),
|
|
10610
|
+
questionText: z42.string().optional(),
|
|
10611
|
+
questionFieldIds: z42.array(z42.string()).optional(),
|
|
10612
|
+
lookupRequests: z42.array(LookupRequestSchema).optional()
|
|
10613
|
+
});
|
|
10614
|
+
var ParsedAnswerSchema = z42.object({
|
|
10615
|
+
fieldId: z42.string(),
|
|
10616
|
+
value: z42.string(),
|
|
10617
|
+
explanation: z42.string().optional()
|
|
10618
|
+
});
|
|
10619
|
+
var AnswerParsingResultSchema = z42.object({
|
|
10620
|
+
answers: z42.array(ParsedAnswerSchema),
|
|
10621
|
+
unanswered: z42.array(z42.string()).describe("Field IDs that were not answered")
|
|
10622
|
+
});
|
|
10623
|
+
var LookupFillSchema = z42.object({
|
|
10624
|
+
fieldId: z42.string(),
|
|
10625
|
+
value: z42.string(),
|
|
10626
|
+
source: z42.string().describe("Specific citable reference, e.g. 'GL Policy #POL-12345 (Hartford)'"),
|
|
10627
|
+
sourceSpanIds: z42.array(z42.string()).optional()
|
|
10628
|
+
});
|
|
10629
|
+
var LookupFillResultSchema = z42.object({
|
|
10630
|
+
fills: z42.array(LookupFillSchema),
|
|
10631
|
+
unfillable: z42.array(z42.string()),
|
|
10632
|
+
explanation: z42.string().optional()
|
|
10633
|
+
});
|
|
10634
|
+
var FlatPdfPlacementSchema = z42.object({
|
|
10635
|
+
fieldId: z42.string(),
|
|
10636
|
+
page: z42.number(),
|
|
10637
|
+
x: z42.number().describe("Percentage from left edge (0-100)"),
|
|
10638
|
+
y: z42.number().describe("Percentage from top edge (0-100)"),
|
|
10639
|
+
text: z42.string(),
|
|
10640
|
+
fontSize: z42.number().optional(),
|
|
10641
|
+
isCheckmark: z42.boolean().optional()
|
|
10642
|
+
});
|
|
10643
|
+
var AcroFormMappingSchema = z42.object({
|
|
10644
|
+
fieldId: z42.string(),
|
|
10645
|
+
acroFormName: z42.string(),
|
|
10646
|
+
value: z42.string()
|
|
10647
|
+
});
|
|
10648
|
+
var QualityGateStatusSchema = z42.enum(["passed", "warning", "failed"]);
|
|
10649
|
+
var QualitySeveritySchema = z42.enum(["info", "warning", "blocking"]);
|
|
10650
|
+
var ApplicationQualityIssueSchema = z42.object({
|
|
10651
|
+
code: z42.string(),
|
|
9573
10652
|
severity: QualitySeveritySchema,
|
|
9574
|
-
message:
|
|
9575
|
-
fieldId:
|
|
10653
|
+
message: z42.string(),
|
|
10654
|
+
fieldId: z42.string().optional()
|
|
9576
10655
|
});
|
|
9577
|
-
var ApplicationQualityRoundSchema =
|
|
9578
|
-
round:
|
|
9579
|
-
kind:
|
|
10656
|
+
var ApplicationQualityRoundSchema = z42.object({
|
|
10657
|
+
round: z42.number(),
|
|
10658
|
+
kind: z42.string(),
|
|
9580
10659
|
status: QualityGateStatusSchema,
|
|
9581
|
-
summary:
|
|
10660
|
+
summary: z42.string().optional()
|
|
9582
10661
|
});
|
|
9583
|
-
var ApplicationQualityArtifactSchema =
|
|
9584
|
-
kind:
|
|
9585
|
-
label:
|
|
9586
|
-
itemCount:
|
|
10662
|
+
var ApplicationQualityArtifactSchema = z42.object({
|
|
10663
|
+
kind: z42.string(),
|
|
10664
|
+
label: z42.string().optional(),
|
|
10665
|
+
itemCount: z42.number().optional()
|
|
9587
10666
|
});
|
|
9588
|
-
var ApplicationEmailReviewSchema =
|
|
9589
|
-
issues:
|
|
10667
|
+
var ApplicationEmailReviewSchema = z42.object({
|
|
10668
|
+
issues: z42.array(ApplicationQualityIssueSchema),
|
|
9590
10669
|
qualityGateStatus: QualityGateStatusSchema
|
|
9591
10670
|
});
|
|
9592
|
-
var ApplicationQualityReportSchema =
|
|
9593
|
-
issues:
|
|
9594
|
-
rounds:
|
|
9595
|
-
artifacts:
|
|
10671
|
+
var ApplicationQualityReportSchema = z42.object({
|
|
10672
|
+
issues: z42.array(ApplicationQualityIssueSchema),
|
|
10673
|
+
rounds: z42.array(ApplicationQualityRoundSchema).optional(),
|
|
10674
|
+
artifacts: z42.array(ApplicationQualityArtifactSchema).optional(),
|
|
9596
10675
|
emailReview: ApplicationEmailReviewSchema.optional(),
|
|
9597
10676
|
qualityGateStatus: QualityGateStatusSchema
|
|
9598
10677
|
});
|
|
9599
|
-
var ApplicationStateSchema =
|
|
9600
|
-
id:
|
|
9601
|
-
pdfBase64:
|
|
9602
|
-
title:
|
|
9603
|
-
applicationType:
|
|
9604
|
-
fields:
|
|
9605
|
-
batches:
|
|
9606
|
-
currentBatchIndex:
|
|
10678
|
+
var ApplicationStateSchema = z42.object({
|
|
10679
|
+
id: z42.string(),
|
|
10680
|
+
pdfBase64: z42.string().optional().describe("Original PDF, omitted after extraction"),
|
|
10681
|
+
title: z42.string().optional(),
|
|
10682
|
+
applicationType: z42.string().nullable().optional(),
|
|
10683
|
+
fields: z42.array(ApplicationFieldSchema),
|
|
10684
|
+
batches: z42.array(z42.array(z42.string())).optional(),
|
|
10685
|
+
currentBatchIndex: z42.number().default(0),
|
|
9607
10686
|
qualityReport: ApplicationQualityReportSchema.optional(),
|
|
9608
|
-
status:
|
|
9609
|
-
createdAt:
|
|
9610
|
-
updatedAt:
|
|
10687
|
+
status: z42.enum(["classifying", "extracting", "auto_filling", "batching", "collecting", "confirming", "mapping", "complete"]),
|
|
10688
|
+
createdAt: z42.number(),
|
|
10689
|
+
updatedAt: z42.number()
|
|
9611
10690
|
});
|
|
9612
10691
|
|
|
9613
10692
|
// src/application/agents/classifier.ts
|
|
@@ -10962,104 +12041,106 @@ Respond with the final answer, deduplicated citations array, overall confidence
|
|
|
10962
12041
|
}
|
|
10963
12042
|
|
|
10964
12043
|
// src/schemas/query.ts
|
|
10965
|
-
import { z as
|
|
10966
|
-
var QueryIntentSchema =
|
|
12044
|
+
import { z as z43 } from "zod";
|
|
12045
|
+
var QueryIntentSchema = z43.enum([
|
|
10967
12046
|
"policy_question",
|
|
10968
12047
|
"coverage_comparison",
|
|
10969
12048
|
"document_search",
|
|
10970
12049
|
"claims_inquiry",
|
|
10971
12050
|
"general_knowledge"
|
|
10972
12051
|
]);
|
|
10973
|
-
var QueryAttachmentKindSchema =
|
|
10974
|
-
var QueryAttachmentSchema =
|
|
10975
|
-
id:
|
|
12052
|
+
var QueryAttachmentKindSchema = z43.enum(["image", "pdf", "text"]);
|
|
12053
|
+
var QueryAttachmentSchema = z43.object({
|
|
12054
|
+
id: z43.string().optional().describe("Optional stable attachment ID from the caller"),
|
|
10976
12055
|
kind: QueryAttachmentKindSchema,
|
|
10977
|
-
name:
|
|
10978
|
-
mimeType:
|
|
10979
|
-
base64:
|
|
10980
|
-
text:
|
|
10981
|
-
description:
|
|
12056
|
+
name: z43.string().optional().describe("Original filename or user-facing label"),
|
|
12057
|
+
mimeType: z43.string().optional().describe("MIME type such as image/jpeg or application/pdf"),
|
|
12058
|
+
base64: z43.string().optional().describe("Base64-encoded file content for image/pdf attachments"),
|
|
12059
|
+
text: z43.string().optional().describe("Plain-text attachment content when available"),
|
|
12060
|
+
description: z43.string().optional().describe("Caller-provided description of the attachment")
|
|
10982
12061
|
});
|
|
10983
|
-
var QueryRetrievalModeSchema =
|
|
12062
|
+
var QueryRetrievalModeSchema = z43.enum([
|
|
10984
12063
|
"graph_only",
|
|
10985
12064
|
"source_rag",
|
|
10986
12065
|
"long_context",
|
|
10987
12066
|
"hybrid"
|
|
10988
12067
|
]);
|
|
10989
|
-
var SubQuestionSchema =
|
|
10990
|
-
question:
|
|
12068
|
+
var SubQuestionSchema = z43.object({
|
|
12069
|
+
question: z43.string().describe("Atomic sub-question to retrieve and answer independently"),
|
|
10991
12070
|
intent: QueryIntentSchema,
|
|
10992
|
-
chunkTypes:
|
|
10993
|
-
documentFilters:
|
|
10994
|
-
type:
|
|
10995
|
-
carrier:
|
|
10996
|
-
insuredName:
|
|
10997
|
-
policyNumber:
|
|
10998
|
-
quoteNumber:
|
|
10999
|
-
policyTypes:
|
|
12071
|
+
chunkTypes: z43.array(z43.string()).optional().describe("Chunk types to filter retrieval (e.g. coverage, endorsement, declaration)"),
|
|
12072
|
+
documentFilters: z43.object({
|
|
12073
|
+
type: z43.enum(["policy", "quote"]).optional(),
|
|
12074
|
+
carrier: z43.string().optional(),
|
|
12075
|
+
insuredName: z43.string().optional(),
|
|
12076
|
+
policyNumber: z43.string().optional(),
|
|
12077
|
+
quoteNumber: z43.string().optional(),
|
|
12078
|
+
policyTypes: z43.array(PolicyTypeSchema).optional().describe("Filter by policy type (e.g. homeowners_ho3, renters_ho4, pet) to avoid mixing up similar policies")
|
|
11000
12079
|
}).optional().describe("Structured filters to narrow document lookup")
|
|
11001
12080
|
});
|
|
11002
|
-
var QueryClassifyResultSchema =
|
|
12081
|
+
var QueryClassifyResultSchema = z43.object({
|
|
11003
12082
|
intent: QueryIntentSchema,
|
|
11004
|
-
subQuestions:
|
|
11005
|
-
requiresDocumentLookup:
|
|
11006
|
-
requiresChunkSearch:
|
|
11007
|
-
requiresConversationHistory:
|
|
12083
|
+
subQuestions: z43.array(SubQuestionSchema).min(1).describe("Decomposed atomic sub-questions"),
|
|
12084
|
+
requiresDocumentLookup: z43.boolean().describe("Whether structured document lookup is needed"),
|
|
12085
|
+
requiresChunkSearch: z43.boolean().describe("Whether semantic chunk search is needed"),
|
|
12086
|
+
requiresConversationHistory: z43.boolean().describe("Whether conversation history is relevant"),
|
|
11008
12087
|
retrievalMode: QueryRetrievalModeSchema.optional().describe("Preferred retrieval strategy for the query when source-span retrieval is available")
|
|
11009
12088
|
});
|
|
11010
|
-
var EvidenceItemSchema =
|
|
11011
|
-
source:
|
|
11012
|
-
chunkId:
|
|
11013
|
-
|
|
11014
|
-
|
|
11015
|
-
|
|
11016
|
-
|
|
11017
|
-
|
|
11018
|
-
|
|
12089
|
+
var EvidenceItemSchema = z43.object({
|
|
12090
|
+
source: z43.enum(["chunk", "document", "conversation", "attachment", "source_span", "source_node"]),
|
|
12091
|
+
chunkId: z43.string().optional(),
|
|
12092
|
+
sourceNodeId: z43.string().optional(),
|
|
12093
|
+
sourceSpanId: z43.string().optional(),
|
|
12094
|
+
documentId: z43.string().optional(),
|
|
12095
|
+
turnId: z43.string().optional(),
|
|
12096
|
+
attachmentId: z43.string().optional(),
|
|
12097
|
+
text: z43.string().describe("Text excerpt from the source"),
|
|
12098
|
+
relevance: z43.number().min(0).max(1),
|
|
11019
12099
|
retrievalMode: QueryRetrievalModeSchema.optional(),
|
|
11020
12100
|
sourceLocation: SourceSpanLocationSchema.optional(),
|
|
11021
|
-
metadata:
|
|
11022
|
-
});
|
|
11023
|
-
var AttachmentInterpretationSchema =
|
|
11024
|
-
summary:
|
|
11025
|
-
extractedFacts:
|
|
11026
|
-
recommendedFocus:
|
|
11027
|
-
confidence:
|
|
11028
|
-
});
|
|
11029
|
-
var RetrievalResultSchema =
|
|
11030
|
-
subQuestion:
|
|
11031
|
-
evidence:
|
|
11032
|
-
});
|
|
11033
|
-
var CitationSchema =
|
|
11034
|
-
index:
|
|
11035
|
-
chunkId:
|
|
11036
|
-
|
|
11037
|
-
|
|
11038
|
-
|
|
11039
|
-
|
|
11040
|
-
|
|
11041
|
-
|
|
12101
|
+
metadata: z43.array(z43.object({ key: z43.string(), value: z43.string() })).optional()
|
|
12102
|
+
});
|
|
12103
|
+
var AttachmentInterpretationSchema = z43.object({
|
|
12104
|
+
summary: z43.string().describe("Concise summary of what the attachment shows or contains"),
|
|
12105
|
+
extractedFacts: z43.array(z43.string()).describe("Specific observable or document facts grounded in the attachment"),
|
|
12106
|
+
recommendedFocus: z43.array(z43.string()).describe("Important details to incorporate when answering follow-up questions"),
|
|
12107
|
+
confidence: z43.number().min(0).max(1)
|
|
12108
|
+
});
|
|
12109
|
+
var RetrievalResultSchema = z43.object({
|
|
12110
|
+
subQuestion: z43.string(),
|
|
12111
|
+
evidence: z43.array(EvidenceItemSchema)
|
|
12112
|
+
});
|
|
12113
|
+
var CitationSchema = z43.object({
|
|
12114
|
+
index: z43.number().describe("Citation number [1], [2], etc."),
|
|
12115
|
+
chunkId: z43.string().optional().describe("Source chunk ID, e.g. doc-123:coverage:2"),
|
|
12116
|
+
sourceNodeId: z43.string().optional().describe("Source tree node ID when available"),
|
|
12117
|
+
sourceSpanId: z43.string().optional().describe("Precise source span ID when available"),
|
|
12118
|
+
documentId: z43.string(),
|
|
12119
|
+
documentType: z43.enum(["policy", "quote"]).optional(),
|
|
12120
|
+
field: z43.string().optional().describe("Specific field path, e.g. coverages[0].deductible"),
|
|
12121
|
+
quote: z43.string().describe("Exact text from source that supports the claim"),
|
|
12122
|
+
relevance: z43.number().min(0).max(1),
|
|
11042
12123
|
retrievalMode: QueryRetrievalModeSchema.optional(),
|
|
11043
12124
|
sourceLocation: SourceSpanLocationSchema.optional()
|
|
11044
12125
|
});
|
|
11045
|
-
var SubAnswerSchema =
|
|
11046
|
-
subQuestion:
|
|
11047
|
-
answer:
|
|
11048
|
-
citations:
|
|
11049
|
-
confidence:
|
|
11050
|
-
needsMoreContext:
|
|
11051
|
-
});
|
|
11052
|
-
var VerifyResultSchema =
|
|
11053
|
-
approved:
|
|
11054
|
-
issues:
|
|
11055
|
-
retrySubQuestions:
|
|
11056
|
-
});
|
|
11057
|
-
var QueryResultSchema =
|
|
11058
|
-
answer:
|
|
11059
|
-
citations:
|
|
12126
|
+
var SubAnswerSchema = z43.object({
|
|
12127
|
+
subQuestion: z43.string(),
|
|
12128
|
+
answer: z43.string(),
|
|
12129
|
+
citations: z43.array(CitationSchema),
|
|
12130
|
+
confidence: z43.number().min(0).max(1),
|
|
12131
|
+
needsMoreContext: z43.boolean().describe("True if evidence was insufficient to answer fully")
|
|
12132
|
+
});
|
|
12133
|
+
var VerifyResultSchema = z43.object({
|
|
12134
|
+
approved: z43.boolean().describe("Whether all sub-answers are adequately grounded"),
|
|
12135
|
+
issues: z43.array(z43.string()).describe("Specific grounding or consistency issues found"),
|
|
12136
|
+
retrySubQuestions: z43.array(z43.string()).optional().describe("Sub-questions that need additional retrieval or re-reasoning")
|
|
12137
|
+
});
|
|
12138
|
+
var QueryResultSchema = z43.object({
|
|
12139
|
+
answer: z43.string(),
|
|
12140
|
+
citations: z43.array(CitationSchema),
|
|
11060
12141
|
intent: QueryIntentSchema,
|
|
11061
|
-
confidence:
|
|
11062
|
-
followUp:
|
|
12142
|
+
confidence: z43.number().min(0).max(1),
|
|
12143
|
+
followUp: z43.string().optional().describe("Suggested follow-up question if applicable")
|
|
11063
12144
|
});
|
|
11064
12145
|
|
|
11065
12146
|
// src/query/retriever.ts
|
|
@@ -11074,6 +12155,35 @@ async function retrieve(subQuestion, conversationId, config) {
|
|
|
11074
12155
|
tasks.push(
|
|
11075
12156
|
(async () => {
|
|
11076
12157
|
try {
|
|
12158
|
+
const nodeResults = await sourceRetriever?.searchSourceNodes?.({
|
|
12159
|
+
question: subQuestion.question,
|
|
12160
|
+
limit: retrievalLimit,
|
|
12161
|
+
mode: retrievalMode
|
|
12162
|
+
}) ?? [];
|
|
12163
|
+
for (const result of nodeResults) {
|
|
12164
|
+
const hierarchyText = result.hierarchy.map((node) => `${node.path} ${node.title}: ${node.textExcerpt ?? node.description}`).join("\n");
|
|
12165
|
+
const spanText = result.spans.map((span) => `[source-span:${span.id}${span.pageStart ? ` p.${span.pageStart}` : ""}]
|
|
12166
|
+
${span.text}`).join("\n\n");
|
|
12167
|
+
evidence.push({
|
|
12168
|
+
source: "source_node",
|
|
12169
|
+
sourceNodeId: result.node.id,
|
|
12170
|
+
sourceSpanId: result.spans[0]?.id,
|
|
12171
|
+
documentId: result.node.documentId,
|
|
12172
|
+
text: [hierarchyText, spanText].filter(Boolean).join("\n\n"),
|
|
12173
|
+
relevance: result.relevance,
|
|
12174
|
+
retrievalMode,
|
|
12175
|
+
sourceLocation: result.spans[0]?.location ?? (result.node.pageStart ? { page: result.node.pageStart } : void 0),
|
|
12176
|
+
metadata: [
|
|
12177
|
+
{ key: "kind", value: result.node.kind },
|
|
12178
|
+
{ key: "path", value: result.node.path },
|
|
12179
|
+
{ key: "title", value: result.node.title },
|
|
12180
|
+
...result.node.metadata ? recordToKVArray(Object.fromEntries(
|
|
12181
|
+
Object.entries(result.node.metadata).filter(([, value]) => typeof value === "string").map(([key, value]) => [key, value])
|
|
12182
|
+
)) : []
|
|
12183
|
+
]
|
|
12184
|
+
});
|
|
12185
|
+
}
|
|
12186
|
+
if (nodeResults.length > 0) return;
|
|
11077
12187
|
const sourceResults = await sourceRetriever?.searchSourceSpans({
|
|
11078
12188
|
question: subQuestion.question,
|
|
11079
12189
|
limit: retrievalLimit,
|
|
@@ -11093,7 +12203,7 @@ async function retrieve(subQuestion, conversationId, config) {
|
|
|
11093
12203
|
});
|
|
11094
12204
|
}
|
|
11095
12205
|
} catch (e) {
|
|
11096
|
-
await log?.(`Source
|
|
12206
|
+
await log?.(`Source tree search failed for "${subQuestion.question}": ${e}`);
|
|
11097
12207
|
}
|
|
11098
12208
|
})()
|
|
11099
12209
|
);
|
|
@@ -11295,7 +12405,7 @@ Answer the sub-question based on the evidence above. For every factual claim, in
|
|
|
11295
12405
|
async function reason(subQuestion, intent, evidence, config) {
|
|
11296
12406
|
const { generateObject, providerOptions } = config;
|
|
11297
12407
|
const evidenceText = evidence.map((e, i) => {
|
|
11298
|
-
const sourceLabel = e.source === "source_span" ? `[source-span:${e.sourceSpanId}]` : e.source === "chunk" ? `[chunk:${e.chunkId}]` : e.source === "document" ? `[doc:${e.documentId}]` : e.source === "attachment" ? `[attachment:${e.attachmentId}]` : `[turn:${e.turnId}]`;
|
|
12408
|
+
const sourceLabel = e.source === "source_node" ? `[source-node:${e.sourceNodeId} source-span:${e.sourceSpanId ?? "none"}]` : e.source === "source_span" ? `[source-span:${e.sourceSpanId}]` : e.source === "chunk" ? `[chunk:${e.chunkId}]` : e.source === "document" ? `[doc:${e.documentId}]` : e.source === "attachment" ? `[attachment:${e.attachmentId}]` : `[turn:${e.turnId}]`;
|
|
11299
12409
|
return `Evidence ${i + 1} ${sourceLabel} (relevance: ${e.relevance.toFixed(2)}):
|
|
11300
12410
|
${e.text}`;
|
|
11301
12411
|
}).join("\n\n");
|
|
@@ -12097,7 +13207,7 @@ ${sa.answer}`).join("\n\n"),
|
|
|
12097
13207
|
}
|
|
12098
13208
|
|
|
12099
13209
|
// src/pce/index.ts
|
|
12100
|
-
import { z as
|
|
13210
|
+
import { z as z44 } from "zod";
|
|
12101
13211
|
|
|
12102
13212
|
// src/prompts/pce/index.ts
|
|
12103
13213
|
function buildPceNormalizePrompt(input) {
|
|
@@ -12131,11 +13241,11 @@ ${input.openQuestions.map((question) => `- ${question.id}${question.fieldPath ?
|
|
|
12131
13241
|
}
|
|
12132
13242
|
|
|
12133
13243
|
// src/pce/index.ts
|
|
12134
|
-
var ReplyAnswersSchema =
|
|
12135
|
-
answers:
|
|
12136
|
-
questionId:
|
|
12137
|
-
fieldPath:
|
|
12138
|
-
answer:
|
|
13244
|
+
var ReplyAnswersSchema = z44.object({
|
|
13245
|
+
answers: z44.array(z44.object({
|
|
13246
|
+
questionId: z44.string().optional(),
|
|
13247
|
+
fieldPath: z44.string().optional(),
|
|
13248
|
+
answer: z44.string()
|
|
12139
13249
|
}))
|
|
12140
13250
|
});
|
|
12141
13251
|
function createPceAgent(config = {}) {
|
|
@@ -12965,6 +14075,8 @@ export {
|
|
|
12965
14075
|
DocumentMetadataSchema,
|
|
12966
14076
|
DocumentNodeSchema,
|
|
12967
14077
|
DocumentPageMapEntrySchema,
|
|
14078
|
+
DocumentSourceNodeKindSchema,
|
|
14079
|
+
DocumentSourceNodeSchema,
|
|
12968
14080
|
DocumentTableOfContentsEntrySchema,
|
|
12969
14081
|
DocumentTypeSchema,
|
|
12970
14082
|
DriverRecordSchema,
|
|
@@ -13020,6 +14132,9 @@ export {
|
|
|
13020
14132
|
MemorySourceStore,
|
|
13021
14133
|
MissingInfoQuestionSchema,
|
|
13022
14134
|
NamedInsuredSchema,
|
|
14135
|
+
OperationalCoverageLineSchema,
|
|
14136
|
+
OperationalEndorsementSupportSchema,
|
|
14137
|
+
OperationalPartySchema,
|
|
13023
14138
|
PERSONAL_AUTO_USAGES,
|
|
13024
14139
|
PET_SPECIES,
|
|
13025
14140
|
PLATFORM_CONFIGS,
|
|
@@ -13049,6 +14164,7 @@ export {
|
|
|
13049
14164
|
PolicyChangeStatusSchema,
|
|
13050
14165
|
PolicyConditionSchema,
|
|
13051
14166
|
PolicyDocumentSchema,
|
|
14167
|
+
PolicyOperationalProfileSchema,
|
|
13052
14168
|
PolicySectionTypeSchema,
|
|
13053
14169
|
PolicyTermTypeSchema,
|
|
13054
14170
|
PolicyTypeSchema,
|
|
@@ -13080,6 +14196,7 @@ export {
|
|
|
13080
14196
|
ScheduledItemCategorySchema,
|
|
13081
14197
|
SectionSchema,
|
|
13082
14198
|
SharedLimitSchema,
|
|
14199
|
+
SourceBackedValueSchema,
|
|
13083
14200
|
SourceChunkSchema,
|
|
13084
14201
|
SourceKindSchema,
|
|
13085
14202
|
SourceSpanBBoxSchema,
|
|
@@ -13121,7 +14238,9 @@ export {
|
|
|
13121
14238
|
buildConfirmationSummaryPrompt,
|
|
13122
14239
|
buildConversationMemoryGuidance,
|
|
13123
14240
|
buildCoverageGapPrompt,
|
|
14241
|
+
buildDeterministicOperationalProfile,
|
|
13124
14242
|
buildDoclingProviderOptions,
|
|
14243
|
+
buildDocumentSourceTree,
|
|
13125
14244
|
buildFieldExplanationPrompt,
|
|
13126
14245
|
buildFieldExtractionPrompt,
|
|
13127
14246
|
buildFlatPdfMappingPrompt,
|
|
@@ -13170,9 +14289,11 @@ export {
|
|
|
13170
14289
|
getTemplate,
|
|
13171
14290
|
isDoclingExtractionInput,
|
|
13172
14291
|
isFileReference,
|
|
14292
|
+
mergeOperationalProfile,
|
|
13173
14293
|
mergeQuestionAnswers,
|
|
13174
14294
|
mergeSourceSpans,
|
|
13175
14295
|
normalizeDoclingDocument,
|
|
14296
|
+
normalizeDocumentSourceTreePaths,
|
|
13176
14297
|
normalizeForMatch,
|
|
13177
14298
|
orderSourceEvidence,
|
|
13178
14299
|
overlayTextOnPdf,
|