@absolutejs/absolute 0.19.0-beta.604 → 0.19.0-beta.605

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.
Files changed (45) hide show
  1. package/dist/ai/client/index.js +186 -6
  2. package/dist/ai/client/index.js.map +4 -4
  3. package/dist/ai/client/ui.js +190 -6
  4. package/dist/ai/client/ui.js.map +4 -4
  5. package/dist/ai/index.js +289 -36
  6. package/dist/ai/index.js.map +7 -7
  7. package/dist/ai/rag/quality.js +17 -6
  8. package/dist/ai/rag/quality.js.map +3 -3
  9. package/dist/ai/rag/ui.js +190 -6
  10. package/dist/ai/rag/ui.js.map +4 -4
  11. package/dist/ai-client/angular/ai/index.js +185 -5
  12. package/dist/ai-client/react/ai/index.js +200 -6
  13. package/dist/ai-client/vue/ai/index.js +289 -97
  14. package/dist/angular/ai/index.js +186 -6
  15. package/dist/angular/ai/index.js.map +4 -4
  16. package/dist/angular/index.js +2 -2
  17. package/dist/angular/index.js.map +1 -1
  18. package/dist/angular/server.js +2 -2
  19. package/dist/angular/server.js.map +1 -1
  20. package/dist/build.js +2 -2
  21. package/dist/build.js.map +1 -1
  22. package/dist/index.js +2 -2
  23. package/dist/index.js.map +1 -1
  24. package/dist/react/ai/index.js +201 -7
  25. package/dist/react/ai/index.js.map +6 -6
  26. package/dist/src/ai/client/ui.d.ts +1 -1
  27. package/dist/src/ai/rag/index.d.ts +1 -1
  28. package/dist/src/ai/rag/presentation.d.ts +7 -1
  29. package/dist/src/ai/rag/ui.d.ts +1 -1
  30. package/dist/src/react/ai/useRAG.d.ts +5 -0
  31. package/dist/src/react/ai/useRAGChunkPreview.d.ts +4 -0
  32. package/dist/src/react/ai/useRAGSources.d.ts +1 -0
  33. package/dist/src/svelte/ai/createRAG.d.ts +5 -0
  34. package/dist/src/svelte/ai/createRAGChunkPreview.d.ts +4 -0
  35. package/dist/src/svelte/ai/createRAGSources.d.ts +1 -0
  36. package/dist/src/vue/ai/useRAG.d.ts +65 -0
  37. package/dist/src/vue/ai/useRAGChunkPreview.d.ts +34 -0
  38. package/dist/src/vue/ai/useRAGSearch.d.ts +30 -0
  39. package/dist/src/vue/ai/useRAGSources.d.ts +1 -0
  40. package/dist/svelte/ai/index.js +247 -53
  41. package/dist/svelte/ai/index.js.map +6 -6
  42. package/dist/types/ai.d.ts +60 -0
  43. package/dist/vue/ai/index.js +253 -59
  44. package/dist/vue/ai/index.js.map +6 -6
  45. package/package.json +1 -1
@@ -765,6 +765,11 @@ var buildContextLabel = (metadata) => {
765
765
  if (speaker) {
766
766
  return `Speaker ${speaker}`;
767
767
  }
768
+ const sectionPath = Array.isArray(metadata.sectionPath) ? metadata.sectionPath.map((value) => getContextString(value)).filter((value) => typeof value === "string") : [];
769
+ const sectionTitle = getContextString(metadata.sectionTitle) ?? sectionPath.at(-1);
770
+ if (sectionTitle) {
771
+ return `Section ${sectionTitle}`;
772
+ }
768
773
  return;
769
774
  };
770
775
  var formatMediaTimestamp = (value) => {
@@ -814,6 +819,10 @@ var buildLocatorLabel = (metadata, source, title) => {
814
819
  if (mediaStart) {
815
820
  return `Timestamp ${mediaStart}`;
816
821
  }
822
+ const sectionPath = Array.isArray(metadata.sectionPath) ? metadata.sectionPath.map((value) => getContextString(value)).filter((value) => typeof value === "string") : [];
823
+ if (sectionPath.length > 0) {
824
+ return `Section ${sectionPath.join(" > ")}`;
825
+ }
817
826
  return;
818
827
  };
819
828
  var formatTimestampLabel = (value) => {
@@ -863,8 +872,10 @@ var buildExcerpt = (text, maxLength = 160) => {
863
872
  var buildGroundingReferenceEvidenceLabel = (reference) => [reference.label, reference.locatorLabel, reference.contextLabel].filter((value) => Boolean(value && value.length > 0)).filter((value, index, values) => values.findIndex((entry) => entry === value) === index).join(" · ");
864
873
  var buildGroundingReferenceEvidenceSummary = (reference) => [
865
874
  reference.source ?? reference.title ?? reference.chunkId,
875
+ reference.locatorLabel,
876
+ reference.contextLabel,
866
877
  reference.provenanceLabel
867
- ].filter((value) => Boolean(value && value.length > 0)).join(" · ");
878
+ ].filter((value) => Boolean(value && value.length > 0)).filter((value, index, values) => values.findIndex((entry) => entry === value) === index).join(" · ");
868
879
  var buildGroundedAnswerCitationDetail = (reference) => ({
869
880
  contextLabel: reference.contextLabel,
870
881
  evidenceLabel: buildGroundingReferenceEvidenceLabel(reference),
@@ -888,12 +899,12 @@ var buildRAGCitations = (sources) => {
888
899
  continue;
889
900
  unique.set(key, {
890
901
  chunkId: source.chunkId,
891
- contextLabel: buildContextLabel(source.metadata),
902
+ contextLabel: source.labels?.contextLabel ?? buildContextLabel(source.metadata),
892
903
  key,
893
904
  label: buildSourceLabel(source),
894
- locatorLabel: buildLocatorLabel(source.metadata, source.source, source.title),
905
+ locatorLabel: source.labels?.locatorLabel ?? buildLocatorLabel(source.metadata, source.source, source.title),
895
906
  metadata: source.metadata,
896
- provenanceLabel: buildProvenanceLabel(source.metadata),
907
+ provenanceLabel: source.labels?.provenanceLabel ?? buildProvenanceLabel(source.metadata),
897
908
  score: source.score,
898
909
  source: source.source,
899
910
  text: source.text,
@@ -963,7 +974,7 @@ var buildRAGGroundingReferences = (sources) => {
963
974
  const citationReferenceMap = buildRAGCitationReferenceMap(citations);
964
975
  return citations.map((citation) => ({
965
976
  chunkId: citation.chunkId,
966
- contextLabel: buildContextLabel(citation.metadata),
977
+ contextLabel: citation.contextLabel ?? buildContextLabel(citation.metadata),
967
978
  excerpt: buildExcerpt(citation.text),
968
979
  label: citation.label,
969
980
  locatorLabel: citation.locatorLabel ?? buildLocatorLabel(citation.metadata, citation.source, citation.title),
@@ -1060,6 +1071,11 @@ var buildContextLabel2 = (metadata) => {
1060
1071
  if (speaker) {
1061
1072
  return `Speaker ${speaker}`;
1062
1073
  }
1074
+ const sectionPath = Array.isArray(metadata.sectionPath) ? metadata.sectionPath.map((value) => getContextString2(value)).filter((value) => typeof value === "string") : [];
1075
+ const sectionTitle = getContextString2(metadata.sectionTitle) ?? sectionPath.at(-1);
1076
+ if (sectionTitle) {
1077
+ return `Section ${sectionTitle}`;
1078
+ }
1063
1079
  return;
1064
1080
  };
1065
1081
  var buildLocatorLabel2 = (metadata, source, title) => {
@@ -1099,6 +1115,10 @@ var buildLocatorLabel2 = (metadata, source, title) => {
1099
1115
  if (mediaStart) {
1100
1116
  return `Timestamp ${mediaStart}`;
1101
1117
  }
1118
+ const sectionPath = Array.isArray(metadata.sectionPath) ? metadata.sectionPath.map((value) => getContextString2(value)).filter((value) => typeof value === "string") : [];
1119
+ if (sectionPath.length > 0) {
1120
+ return `Section ${sectionPath.join(" > ")}`;
1121
+ }
1102
1122
  return;
1103
1123
  };
1104
1124
  var buildProvenanceLabel2 = (metadata) => {
@@ -1144,6 +1164,33 @@ var buildRAGSourceLabels = ({
1144
1164
  provenanceLabel
1145
1165
  };
1146
1166
  };
1167
+ var buildRAGChunkStructure = (metadata) => {
1168
+ if (!metadata) {
1169
+ return;
1170
+ }
1171
+ const sectionPath = Array.isArray(metadata.sectionPath) ? metadata.sectionPath.filter((value) => typeof value === "string" && value.trim().length > 0) : undefined;
1172
+ const sectionKind = metadata.sectionKind === "markdown_heading" || metadata.sectionKind === "html_heading" ? metadata.sectionKind : undefined;
1173
+ const section = {
1174
+ depth: getContextNumber2(metadata.sectionDepth),
1175
+ kind: sectionKind,
1176
+ path: sectionPath && sectionPath.length > 0 ? sectionPath : undefined,
1177
+ title: getContextString2(metadata.sectionTitle)
1178
+ };
1179
+ const sequence = {
1180
+ nextChunkId: getContextString2(metadata.nextChunkId),
1181
+ previousChunkId: getContextString2(metadata.previousChunkId),
1182
+ sectionChunkCount: getContextNumber2(metadata.sectionChunkCount),
1183
+ sectionChunkId: getContextString2(metadata.sectionChunkId),
1184
+ sectionChunkIndex: getContextNumber2(metadata.sectionChunkIndex)
1185
+ };
1186
+ if (!section.title && (!section.path || section.path.length === 0) && typeof section.depth !== "number" && !section.kind && !sequence.nextChunkId && !sequence.previousChunkId && typeof sequence.sectionChunkCount !== "number" && !sequence.sectionChunkId && typeof sequence.sectionChunkIndex !== "number") {
1187
+ return;
1188
+ }
1189
+ return {
1190
+ section: section.title || section.path && section.path.length > 0 || typeof section.depth === "number" || section.kind ? section : undefined,
1191
+ sequence: sequence.nextChunkId || sequence.previousChunkId || typeof sequence.sectionChunkCount === "number" || sequence.sectionChunkId || typeof sequence.sectionChunkIndex === "number" ? sequence : undefined
1192
+ };
1193
+ };
1147
1194
  var buildExcerpt2 = (text, maxLength = 160) => {
1148
1195
  const normalized = text.replaceAll(/\s+/g, " ").trim();
1149
1196
  if (normalized.length <= maxLength) {
@@ -1151,6 +1198,136 @@ var buildExcerpt2 = (text, maxLength = 160) => {
1151
1198
  }
1152
1199
  return `${normalized.slice(0, Math.max(0, maxLength - 1)).trimEnd()}…`;
1153
1200
  };
1201
+ var buildRAGChunkGraph = (chunks) => {
1202
+ const nodes = [];
1203
+ const edges = [];
1204
+ const edgeKeys = new Set;
1205
+ const sections = new Map;
1206
+ for (const chunk of chunks) {
1207
+ const labels = chunk.labels ?? buildRAGSourceLabels({
1208
+ metadata: chunk.metadata,
1209
+ source: chunk.source,
1210
+ title: chunk.title
1211
+ });
1212
+ const structure = chunk.structure ?? buildRAGChunkStructure(chunk.metadata);
1213
+ nodes.push({
1214
+ chunkId: chunk.chunkId,
1215
+ contextLabel: labels?.contextLabel,
1216
+ label: chunk.source ?? chunk.title ?? chunk.chunkId,
1217
+ locatorLabel: labels?.locatorLabel,
1218
+ provenanceLabel: labels?.provenanceLabel,
1219
+ score: chunk.score,
1220
+ source: chunk.source,
1221
+ structure,
1222
+ title: chunk.title
1223
+ });
1224
+ const previousChunkId = structure?.sequence?.previousChunkId;
1225
+ if (previousChunkId) {
1226
+ const key = `previous:${previousChunkId}:${chunk.chunkId}`;
1227
+ if (!edgeKeys.has(key)) {
1228
+ edgeKeys.add(key);
1229
+ edges.push({
1230
+ fromChunkId: previousChunkId,
1231
+ relation: "previous",
1232
+ toChunkId: chunk.chunkId
1233
+ });
1234
+ }
1235
+ }
1236
+ const nextChunkId = structure?.sequence?.nextChunkId;
1237
+ if (nextChunkId) {
1238
+ const key = `next:${chunk.chunkId}:${nextChunkId}`;
1239
+ if (!edgeKeys.has(key)) {
1240
+ edgeKeys.add(key);
1241
+ edges.push({
1242
+ fromChunkId: chunk.chunkId,
1243
+ relation: "next",
1244
+ toChunkId: nextChunkId
1245
+ });
1246
+ }
1247
+ }
1248
+ const sectionId = structure?.sequence?.sectionChunkId;
1249
+ if (sectionId) {
1250
+ const existing = sections.get(sectionId);
1251
+ if (!existing) {
1252
+ sections.set(sectionId, {
1253
+ chunkCount: structure.sequence?.sectionChunkCount ?? 1,
1254
+ chunkIds: [chunk.chunkId],
1255
+ depth: structure.section?.depth,
1256
+ id: sectionId,
1257
+ kind: structure.section?.kind,
1258
+ path: structure.section?.path,
1259
+ title: structure.section?.title
1260
+ });
1261
+ continue;
1262
+ }
1263
+ if (!existing.chunkIds.includes(chunk.chunkId)) {
1264
+ existing.chunkIds.push(chunk.chunkId);
1265
+ }
1266
+ existing.chunkCount = Math.max(existing.chunkCount, structure.sequence?.sectionChunkCount ?? existing.chunkCount);
1267
+ }
1268
+ }
1269
+ for (const section of sections.values()) {
1270
+ section.chunkIds.sort((left, right) => {
1271
+ const leftNode = nodes.find((node) => node.chunkId === left);
1272
+ const rightNode = nodes.find((node) => node.chunkId === right);
1273
+ const leftIndex = leftNode?.structure?.sequence?.sectionChunkIndex ?? Number.MAX_SAFE_INTEGER;
1274
+ const rightIndex = rightNode?.structure?.sequence?.sectionChunkIndex ?? Number.MAX_SAFE_INTEGER;
1275
+ if (leftIndex !== rightIndex) {
1276
+ return leftIndex - rightIndex;
1277
+ }
1278
+ return left.localeCompare(right);
1279
+ });
1280
+ }
1281
+ nodes.sort((left, right) => {
1282
+ const leftSection = left.structure?.sequence?.sectionChunkIndex ?? Number.MAX_SAFE_INTEGER;
1283
+ const rightSection = right.structure?.sequence?.sectionChunkIndex ?? Number.MAX_SAFE_INTEGER;
1284
+ if (leftSection !== rightSection) {
1285
+ return leftSection - rightSection;
1286
+ }
1287
+ const leftScore = left.score ?? Number.NEGATIVE_INFINITY;
1288
+ const rightScore = right.score ?? Number.NEGATIVE_INFINITY;
1289
+ if (leftScore !== rightScore) {
1290
+ return rightScore - leftScore;
1291
+ }
1292
+ return left.label.localeCompare(right.label);
1293
+ });
1294
+ return {
1295
+ edges,
1296
+ nodes,
1297
+ sections: [...sections.values()].sort((left, right) => (left.title ?? left.id).localeCompare(right.title ?? right.id))
1298
+ };
1299
+ };
1300
+ var buildRAGChunkPreviewGraph = (preview) => buildRAGChunkGraph(preview.chunks.map((chunk) => ({
1301
+ chunkId: chunk.chunkId,
1302
+ labels: chunk.labels,
1303
+ metadata: chunk.metadata,
1304
+ source: chunk.source ?? preview.document.source,
1305
+ structure: chunk.structure,
1306
+ title: chunk.title ?? preview.document.title
1307
+ })));
1308
+ var buildRAGChunkPreviewNavigation = (preview, activeChunkId) => buildRAGChunkGraphNavigation(buildRAGChunkPreviewGraph(preview), activeChunkId);
1309
+ var buildRAGChunkGraphNavigation = (graph, activeChunkId) => {
1310
+ if (graph.nodes.length === 0) {
1311
+ return {
1312
+ activeChunkId,
1313
+ sectionNodes: []
1314
+ };
1315
+ }
1316
+ const activeNode = (activeChunkId ? graph.nodes.find((node) => node.chunkId === activeChunkId) : undefined) ?? graph.nodes[0];
1317
+ const resolvedActiveChunkId = activeNode?.chunkId;
1318
+ const previousNode = activeNode?.structure?.sequence?.previousChunkId ? graph.nodes.find((node) => node.chunkId === activeNode.structure?.sequence?.previousChunkId) : undefined;
1319
+ const nextNode = activeNode?.structure?.sequence?.nextChunkId ? graph.nodes.find((node) => node.chunkId === activeNode.structure?.sequence?.nextChunkId) : undefined;
1320
+ const section = activeNode?.structure?.sequence?.sectionChunkId ? graph.sections.find((entry) => entry.id === activeNode.structure?.sequence?.sectionChunkId) : undefined;
1321
+ const sectionNodes = section ? section.chunkIds.map((chunkId) => graph.nodes.find((node) => node.chunkId === chunkId)).filter((node) => Boolean(node)) : activeNode ? [activeNode] : [];
1322
+ return {
1323
+ activeChunkId: resolvedActiveChunkId,
1324
+ activeNode,
1325
+ nextNode,
1326
+ previousNode,
1327
+ section,
1328
+ sectionNodes
1329
+ };
1330
+ };
1154
1331
  var buildRAGRetrievedState = (messages) => {
1155
1332
  const message = getLatestRetrievedMessage(messages);
1156
1333
  if (!message) {
@@ -1192,6 +1369,7 @@ var buildRAGSourceSummaries = (sources) => {
1192
1369
  label: group.label,
1193
1370
  locatorLabel: leadChunk?.labels?.locatorLabel ?? buildLocatorLabel2(leadChunk?.metadata, leadChunk?.source, leadChunk?.title),
1194
1371
  provenanceLabel: leadChunk?.labels?.provenanceLabel ?? buildProvenanceLabel2(leadChunk?.metadata),
1372
+ structure: leadChunk?.structure ?? buildRAGChunkStructure(leadChunk?.metadata),
1195
1373
  source: group.source,
1196
1374
  title: group.title
1197
1375
  };
@@ -1320,6 +1498,7 @@ var buildSourceGroup = (source, key) => ({
1320
1498
  source: source.source,
1321
1499
  title: source.title
1322
1500
  }),
1501
+ structure: source.structure ?? buildRAGChunkStructure(source.metadata),
1323
1502
  source: source.source,
1324
1503
  title: source.title
1325
1504
  });
@@ -1338,6 +1517,7 @@ var updateSourceGroup = (groups, source) => {
1338
1517
  source: source.source,
1339
1518
  title: source.title
1340
1519
  });
1520
+ existing.structure = source.structure ?? buildRAGChunkStructure(source.metadata);
1341
1521
  existing.source = source.source;
1342
1522
  existing.title = source.title;
1343
1523
  } else {
@@ -725,6 +725,11 @@ var buildContextLabel = (metadata) => {
725
725
  if (speaker) {
726
726
  return `Speaker ${speaker}`;
727
727
  }
728
+ const sectionPath = Array.isArray(metadata.sectionPath) ? metadata.sectionPath.map((value) => getContextString(value)).filter((value) => typeof value === "string") : [];
729
+ const sectionTitle = getContextString(metadata.sectionTitle) ?? sectionPath.at(-1);
730
+ if (sectionTitle) {
731
+ return `Section ${sectionTitle}`;
732
+ }
728
733
  return;
729
734
  };
730
735
  var formatMediaTimestamp = (value) => {
@@ -774,6 +779,10 @@ var buildLocatorLabel = (metadata, source, title) => {
774
779
  if (mediaStart) {
775
780
  return `Timestamp ${mediaStart}`;
776
781
  }
782
+ const sectionPath = Array.isArray(metadata.sectionPath) ? metadata.sectionPath.map((value) => getContextString(value)).filter((value) => typeof value === "string") : [];
783
+ if (sectionPath.length > 0) {
784
+ return `Section ${sectionPath.join(" > ")}`;
785
+ }
777
786
  return;
778
787
  };
779
788
  var formatTimestampLabel = (value) => {
@@ -823,8 +832,10 @@ var buildExcerpt = (text, maxLength = 160) => {
823
832
  var buildGroundingReferenceEvidenceLabel = (reference) => [reference.label, reference.locatorLabel, reference.contextLabel].filter((value) => Boolean(value && value.length > 0)).filter((value, index, values) => values.findIndex((entry) => entry === value) === index).join(" · ");
824
833
  var buildGroundingReferenceEvidenceSummary = (reference) => [
825
834
  reference.source ?? reference.title ?? reference.chunkId,
835
+ reference.locatorLabel,
836
+ reference.contextLabel,
826
837
  reference.provenanceLabel
827
- ].filter((value) => Boolean(value && value.length > 0)).join(" · ");
838
+ ].filter((value) => Boolean(value && value.length > 0)).filter((value, index, values) => values.findIndex((entry) => entry === value) === index).join(" · ");
828
839
  var buildGroundedAnswerCitationDetail = (reference) => ({
829
840
  contextLabel: reference.contextLabel,
830
841
  evidenceLabel: buildGroundingReferenceEvidenceLabel(reference),
@@ -848,12 +859,12 @@ var buildRAGCitations = (sources) => {
848
859
  continue;
849
860
  unique.set(key, {
850
861
  chunkId: source.chunkId,
851
- contextLabel: buildContextLabel(source.metadata),
862
+ contextLabel: source.labels?.contextLabel ?? buildContextLabel(source.metadata),
852
863
  key,
853
864
  label: buildSourceLabel(source),
854
- locatorLabel: buildLocatorLabel(source.metadata, source.source, source.title),
865
+ locatorLabel: source.labels?.locatorLabel ?? buildLocatorLabel(source.metadata, source.source, source.title),
855
866
  metadata: source.metadata,
856
- provenanceLabel: buildProvenanceLabel(source.metadata),
867
+ provenanceLabel: source.labels?.provenanceLabel ?? buildProvenanceLabel(source.metadata),
857
868
  score: source.score,
858
869
  source: source.source,
859
870
  text: source.text,
@@ -923,7 +934,7 @@ var buildRAGGroundingReferences = (sources) => {
923
934
  const citationReferenceMap = buildRAGCitationReferenceMap(citations);
924
935
  return citations.map((citation) => ({
925
936
  chunkId: citation.chunkId,
926
- contextLabel: buildContextLabel(citation.metadata),
937
+ contextLabel: citation.contextLabel ?? buildContextLabel(citation.metadata),
927
938
  excerpt: buildExcerpt(citation.text),
928
939
  label: citation.label,
929
940
  locatorLabel: citation.locatorLabel ?? buildLocatorLabel(citation.metadata, citation.source, citation.title),
@@ -1020,6 +1031,11 @@ var buildContextLabel2 = (metadata) => {
1020
1031
  if (speaker) {
1021
1032
  return `Speaker ${speaker}`;
1022
1033
  }
1034
+ const sectionPath = Array.isArray(metadata.sectionPath) ? metadata.sectionPath.map((value) => getContextString2(value)).filter((value) => typeof value === "string") : [];
1035
+ const sectionTitle = getContextString2(metadata.sectionTitle) ?? sectionPath.at(-1);
1036
+ if (sectionTitle) {
1037
+ return `Section ${sectionTitle}`;
1038
+ }
1023
1039
  return;
1024
1040
  };
1025
1041
  var buildLocatorLabel2 = (metadata, source, title) => {
@@ -1059,6 +1075,10 @@ var buildLocatorLabel2 = (metadata, source, title) => {
1059
1075
  if (mediaStart) {
1060
1076
  return `Timestamp ${mediaStart}`;
1061
1077
  }
1078
+ const sectionPath = Array.isArray(metadata.sectionPath) ? metadata.sectionPath.map((value) => getContextString2(value)).filter((value) => typeof value === "string") : [];
1079
+ if (sectionPath.length > 0) {
1080
+ return `Section ${sectionPath.join(" > ")}`;
1081
+ }
1062
1082
  return;
1063
1083
  };
1064
1084
  var buildProvenanceLabel2 = (metadata) => {
@@ -1104,6 +1124,33 @@ var buildRAGSourceLabels = ({
1104
1124
  provenanceLabel
1105
1125
  };
1106
1126
  };
1127
+ var buildRAGChunkStructure = (metadata) => {
1128
+ if (!metadata) {
1129
+ return;
1130
+ }
1131
+ const sectionPath = Array.isArray(metadata.sectionPath) ? metadata.sectionPath.filter((value) => typeof value === "string" && value.trim().length > 0) : undefined;
1132
+ const sectionKind = metadata.sectionKind === "markdown_heading" || metadata.sectionKind === "html_heading" ? metadata.sectionKind : undefined;
1133
+ const section = {
1134
+ depth: getContextNumber2(metadata.sectionDepth),
1135
+ kind: sectionKind,
1136
+ path: sectionPath && sectionPath.length > 0 ? sectionPath : undefined,
1137
+ title: getContextString2(metadata.sectionTitle)
1138
+ };
1139
+ const sequence = {
1140
+ nextChunkId: getContextString2(metadata.nextChunkId),
1141
+ previousChunkId: getContextString2(metadata.previousChunkId),
1142
+ sectionChunkCount: getContextNumber2(metadata.sectionChunkCount),
1143
+ sectionChunkId: getContextString2(metadata.sectionChunkId),
1144
+ sectionChunkIndex: getContextNumber2(metadata.sectionChunkIndex)
1145
+ };
1146
+ if (!section.title && (!section.path || section.path.length === 0) && typeof section.depth !== "number" && !section.kind && !sequence.nextChunkId && !sequence.previousChunkId && typeof sequence.sectionChunkCount !== "number" && !sequence.sectionChunkId && typeof sequence.sectionChunkIndex !== "number") {
1147
+ return;
1148
+ }
1149
+ return {
1150
+ section: section.title || section.path && section.path.length > 0 || typeof section.depth === "number" || section.kind ? section : undefined,
1151
+ sequence: sequence.nextChunkId || sequence.previousChunkId || typeof sequence.sectionChunkCount === "number" || sequence.sectionChunkId || typeof sequence.sectionChunkIndex === "number" ? sequence : undefined
1152
+ };
1153
+ };
1107
1154
  var buildExcerpt2 = (text, maxLength = 160) => {
1108
1155
  const normalized = text.replaceAll(/\s+/g, " ").trim();
1109
1156
  if (normalized.length <= maxLength) {
@@ -1111,6 +1158,136 @@ var buildExcerpt2 = (text, maxLength = 160) => {
1111
1158
  }
1112
1159
  return `${normalized.slice(0, Math.max(0, maxLength - 1)).trimEnd()}…`;
1113
1160
  };
1161
+ var buildRAGChunkGraph = (chunks) => {
1162
+ const nodes = [];
1163
+ const edges = [];
1164
+ const edgeKeys = new Set;
1165
+ const sections = new Map;
1166
+ for (const chunk of chunks) {
1167
+ const labels = chunk.labels ?? buildRAGSourceLabels({
1168
+ metadata: chunk.metadata,
1169
+ source: chunk.source,
1170
+ title: chunk.title
1171
+ });
1172
+ const structure = chunk.structure ?? buildRAGChunkStructure(chunk.metadata);
1173
+ nodes.push({
1174
+ chunkId: chunk.chunkId,
1175
+ contextLabel: labels?.contextLabel,
1176
+ label: chunk.source ?? chunk.title ?? chunk.chunkId,
1177
+ locatorLabel: labels?.locatorLabel,
1178
+ provenanceLabel: labels?.provenanceLabel,
1179
+ score: chunk.score,
1180
+ source: chunk.source,
1181
+ structure,
1182
+ title: chunk.title
1183
+ });
1184
+ const previousChunkId = structure?.sequence?.previousChunkId;
1185
+ if (previousChunkId) {
1186
+ const key = `previous:${previousChunkId}:${chunk.chunkId}`;
1187
+ if (!edgeKeys.has(key)) {
1188
+ edgeKeys.add(key);
1189
+ edges.push({
1190
+ fromChunkId: previousChunkId,
1191
+ relation: "previous",
1192
+ toChunkId: chunk.chunkId
1193
+ });
1194
+ }
1195
+ }
1196
+ const nextChunkId = structure?.sequence?.nextChunkId;
1197
+ if (nextChunkId) {
1198
+ const key = `next:${chunk.chunkId}:${nextChunkId}`;
1199
+ if (!edgeKeys.has(key)) {
1200
+ edgeKeys.add(key);
1201
+ edges.push({
1202
+ fromChunkId: chunk.chunkId,
1203
+ relation: "next",
1204
+ toChunkId: nextChunkId
1205
+ });
1206
+ }
1207
+ }
1208
+ const sectionId = structure?.sequence?.sectionChunkId;
1209
+ if (sectionId) {
1210
+ const existing = sections.get(sectionId);
1211
+ if (!existing) {
1212
+ sections.set(sectionId, {
1213
+ chunkCount: structure.sequence?.sectionChunkCount ?? 1,
1214
+ chunkIds: [chunk.chunkId],
1215
+ depth: structure.section?.depth,
1216
+ id: sectionId,
1217
+ kind: structure.section?.kind,
1218
+ path: structure.section?.path,
1219
+ title: structure.section?.title
1220
+ });
1221
+ continue;
1222
+ }
1223
+ if (!existing.chunkIds.includes(chunk.chunkId)) {
1224
+ existing.chunkIds.push(chunk.chunkId);
1225
+ }
1226
+ existing.chunkCount = Math.max(existing.chunkCount, structure.sequence?.sectionChunkCount ?? existing.chunkCount);
1227
+ }
1228
+ }
1229
+ for (const section of sections.values()) {
1230
+ section.chunkIds.sort((left, right) => {
1231
+ const leftNode = nodes.find((node) => node.chunkId === left);
1232
+ const rightNode = nodes.find((node) => node.chunkId === right);
1233
+ const leftIndex = leftNode?.structure?.sequence?.sectionChunkIndex ?? Number.MAX_SAFE_INTEGER;
1234
+ const rightIndex = rightNode?.structure?.sequence?.sectionChunkIndex ?? Number.MAX_SAFE_INTEGER;
1235
+ if (leftIndex !== rightIndex) {
1236
+ return leftIndex - rightIndex;
1237
+ }
1238
+ return left.localeCompare(right);
1239
+ });
1240
+ }
1241
+ nodes.sort((left, right) => {
1242
+ const leftSection = left.structure?.sequence?.sectionChunkIndex ?? Number.MAX_SAFE_INTEGER;
1243
+ const rightSection = right.structure?.sequence?.sectionChunkIndex ?? Number.MAX_SAFE_INTEGER;
1244
+ if (leftSection !== rightSection) {
1245
+ return leftSection - rightSection;
1246
+ }
1247
+ const leftScore = left.score ?? Number.NEGATIVE_INFINITY;
1248
+ const rightScore = right.score ?? Number.NEGATIVE_INFINITY;
1249
+ if (leftScore !== rightScore) {
1250
+ return rightScore - leftScore;
1251
+ }
1252
+ return left.label.localeCompare(right.label);
1253
+ });
1254
+ return {
1255
+ edges,
1256
+ nodes,
1257
+ sections: [...sections.values()].sort((left, right) => (left.title ?? left.id).localeCompare(right.title ?? right.id))
1258
+ };
1259
+ };
1260
+ var buildRAGChunkPreviewGraph = (preview) => buildRAGChunkGraph(preview.chunks.map((chunk) => ({
1261
+ chunkId: chunk.chunkId,
1262
+ labels: chunk.labels,
1263
+ metadata: chunk.metadata,
1264
+ source: chunk.source ?? preview.document.source,
1265
+ structure: chunk.structure,
1266
+ title: chunk.title ?? preview.document.title
1267
+ })));
1268
+ var buildRAGChunkPreviewNavigation = (preview, activeChunkId) => buildRAGChunkGraphNavigation(buildRAGChunkPreviewGraph(preview), activeChunkId);
1269
+ var buildRAGChunkGraphNavigation = (graph, activeChunkId) => {
1270
+ if (graph.nodes.length === 0) {
1271
+ return {
1272
+ activeChunkId,
1273
+ sectionNodes: []
1274
+ };
1275
+ }
1276
+ const activeNode = (activeChunkId ? graph.nodes.find((node) => node.chunkId === activeChunkId) : undefined) ?? graph.nodes[0];
1277
+ const resolvedActiveChunkId = activeNode?.chunkId;
1278
+ const previousNode = activeNode?.structure?.sequence?.previousChunkId ? graph.nodes.find((node) => node.chunkId === activeNode.structure?.sequence?.previousChunkId) : undefined;
1279
+ const nextNode = activeNode?.structure?.sequence?.nextChunkId ? graph.nodes.find((node) => node.chunkId === activeNode.structure?.sequence?.nextChunkId) : undefined;
1280
+ const section = activeNode?.structure?.sequence?.sectionChunkId ? graph.sections.find((entry) => entry.id === activeNode.structure?.sequence?.sectionChunkId) : undefined;
1281
+ const sectionNodes = section ? section.chunkIds.map((chunkId) => graph.nodes.find((node) => node.chunkId === chunkId)).filter((node) => Boolean(node)) : activeNode ? [activeNode] : [];
1282
+ return {
1283
+ activeChunkId: resolvedActiveChunkId,
1284
+ activeNode,
1285
+ nextNode,
1286
+ previousNode,
1287
+ section,
1288
+ sectionNodes
1289
+ };
1290
+ };
1114
1291
  var buildRAGRetrievedState = (messages) => {
1115
1292
  const message = getLatestRetrievedMessage(messages);
1116
1293
  if (!message) {
@@ -1152,6 +1329,7 @@ var buildRAGSourceSummaries = (sources) => {
1152
1329
  label: group.label,
1153
1330
  locatorLabel: leadChunk?.labels?.locatorLabel ?? buildLocatorLabel2(leadChunk?.metadata, leadChunk?.source, leadChunk?.title),
1154
1331
  provenanceLabel: leadChunk?.labels?.provenanceLabel ?? buildProvenanceLabel2(leadChunk?.metadata),
1332
+ structure: leadChunk?.structure ?? buildRAGChunkStructure(leadChunk?.metadata),
1155
1333
  source: group.source,
1156
1334
  title: group.title
1157
1335
  };
@@ -1280,6 +1458,7 @@ var buildSourceGroup = (source, key) => ({
1280
1458
  source: source.source,
1281
1459
  title: source.title
1282
1460
  }),
1461
+ structure: source.structure ?? buildRAGChunkStructure(source.metadata),
1283
1462
  source: source.source,
1284
1463
  title: source.title
1285
1464
  });
@@ -1298,6 +1477,7 @@ var updateSourceGroup = (groups, source) => {
1298
1477
  source: source.source,
1299
1478
  title: source.title
1300
1479
  });
1480
+ existing.structure = source.structure ?? buildRAGChunkStructure(source.metadata);
1301
1481
  existing.source = source.source;
1302
1482
  existing.title = source.title;
1303
1483
  } else {
@@ -2806,6 +2986,7 @@ var runRAGEvaluationSuite = async ({
2806
2986
  var useRAGChunkPreview = (path) => {
2807
2987
  const client = useMemo(() => createRAGClient({ path }), [path]);
2808
2988
  const [preview, setPreview] = useState(null);
2989
+ const [activeChunkId, setActiveChunkId] = useState(null);
2809
2990
  const [isLoading, setIsLoading] = useState(false);
2810
2991
  const [error, setError] = useState(null);
2811
2992
  const inspect = useCallback2(async (id) => {
@@ -2817,6 +2998,7 @@ var useRAGChunkPreview = (path) => {
2817
2998
  throw new Error(response.error);
2818
2999
  }
2819
3000
  setPreview(response);
3001
+ setActiveChunkId(response.chunks[0]?.chunkId ?? null);
2820
3002
  return response;
2821
3003
  } catch (err) {
2822
3004
  const message = err instanceof Error ? err.message : "Failed to load RAG chunk preview";
@@ -2828,15 +3010,25 @@ var useRAGChunkPreview = (path) => {
2828
3010
  }, [client]);
2829
3011
  const clear = useCallback2(() => {
2830
3012
  setPreview(null);
3013
+ setActiveChunkId(null);
2831
3014
  setError(null);
2832
3015
  setIsLoading(false);
2833
3016
  }, []);
3017
+ const chunkGraph = useMemo(() => preview ? buildRAGChunkPreviewGraph(preview) : null, [preview]);
3018
+ const navigation = useMemo(() => preview ? buildRAGChunkPreviewNavigation(preview, activeChunkId ?? undefined) : null, [activeChunkId, preview]);
3019
+ const selectChunk = useCallback2((id) => {
3020
+ setActiveChunkId(id);
3021
+ }, []);
2834
3022
  return {
3023
+ activeChunkId,
3024
+ chunkGraph,
2835
3025
  clear,
2836
3026
  error,
2837
3027
  inspect,
2838
3028
  isLoading,
2839
- preview
3029
+ navigation,
3030
+ preview,
3031
+ selectChunk
2840
3032
  };
2841
3033
  };
2842
3034
  // src/react/ai/useRAG.ts
@@ -3417,9 +3609,11 @@ var useRAGSources = (messages) => {
3417
3609
  const sources = useMemo10(() => getLatestRAGSources(messages), [messages]);
3418
3610
  const sourceGroups = useMemo10(() => buildRAGSourceGroups(sources), [sources]);
3419
3611
  const sourceSummaries = useMemo10(() => buildRAGSourceSummaries(sources), [sources]);
3612
+ const chunkGraph = useMemo10(() => buildRAGChunkGraph(sources), [sources]);
3420
3613
  const citationReferenceMap = useMemo10(() => buildRAGCitationReferenceMap(sourceSummaries.flatMap((summary) => summary.citations)), [sourceSummaries]);
3421
3614
  return {
3422
3615
  citationReferenceMap,
3616
+ chunkGraph,
3423
3617
  hasSources: sources.length > 0,
3424
3618
  latestAssistantMessage,
3425
3619
  sourceGroups,