@retrivora-ai/rag-engine 1.0.2 → 1.0.4

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.
@@ -1391,29 +1391,59 @@ var EntityExtractor = class {
1391
1391
  async extract(text) {
1392
1392
  const prompt = `
1393
1393
  Extract entities and relationships from the following text.
1394
- Format the output as JSON with two keys: "nodes" (array of {id, label, properties}) and "edges" (array of {source, target, type, properties}).
1395
- Use the same ID for the same entity.
1394
+ Format the output as a JSON object with exactly two keys: "nodes" and "edges".
1396
1395
 
1397
- IMPORTANT: Ensure all property values are valid JSON types (strings, numbers, booleans, or null).
1398
- DO NOT include mathematical expressions like "4.5/5" as numbers; use strings instead.
1396
+ Nodes: {id, label, properties}
1397
+ Edges: {source, target, type, properties}
1399
1398
 
1400
- Text:
1401
- "${text}"
1399
+ IMPORTANT:
1400
+ - Ensure all property values are simple JSON types (string, number, boolean).
1401
+ - Do not use mathematical expressions or complex nested objects in properties.
1402
+ - If no entities are found, return empty arrays.
1403
+ - RESPOND ONLY WITH THE JSON OBJECT.
1402
1404
 
1403
- Output JSON:
1405
+ Text to extract from:
1406
+ "${text}"
1404
1407
  `;
1405
1408
  const response = await this.llm.chat([
1406
- { role: "system", content: "You are an expert at knowledge graph extraction. Respond only with valid JSON." },
1409
+ { role: "system", content: "You are a precise knowledge graph extraction engine. You always output valid JSON and nothing else." },
1407
1410
  { role: "user", content: prompt }
1408
- ], "");
1411
+ ], "", { maxTokens: 4096, temperature: 0.1 });
1409
1412
  try {
1410
- const cleanJson = response.replace(/```json\n?|\n?```/g, "").trim();
1413
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
1414
+ const cleanJson = jsonMatch ? jsonMatch[0] : response.trim();
1411
1415
  return JSON.parse(cleanJson);
1412
1416
  } catch (e) {
1413
- console.warn("[EntityExtractor] Failed to parse LLM response as JSON:", response);
1417
+ try {
1418
+ const repaired = this.repairTruncatedJson(response);
1419
+ if (repaired) return JSON.parse(repaired);
1420
+ } catch (e2) {
1421
+ }
1422
+ console.warn(`[EntityExtractor] Failed to parse LLM response. Length: ${response.length} chars.`);
1423
+ console.warn("[EntityExtractor] Snippet:", response.substring(0, 100) + "...");
1414
1424
  return { nodes: [], edges: [] };
1415
1425
  }
1416
1426
  }
1427
+ /**
1428
+ * Attempts to fix JSON that was cut off mid-generation.
1429
+ * Strategy: Find the last valid element in an array and close the structure.
1430
+ */
1431
+ repairTruncatedJson(json) {
1432
+ let text = json.trim();
1433
+ const startIdx = text.indexOf("{");
1434
+ if (startIdx === -1) return null;
1435
+ text = text.substring(startIdx);
1436
+ const lastCompleteObjectIdx = text.lastIndexOf("}");
1437
+ if (lastCompleteObjectIdx === -1) return null;
1438
+ let repaired = text.substring(0, lastCompleteObjectIdx + 1);
1439
+ const openBrackets = (repaired.match(/\{/g) || []).length;
1440
+ const closedBrackets = (repaired.match(/\}/g) || []).length;
1441
+ const openSquares = (repaired.match(/\[/g) || []).length;
1442
+ const closedSquares = (repaired.match(/\]/g) || []).length;
1443
+ for (let i = 0; i < openSquares - closedSquares; i++) repaired += "]";
1444
+ for (let i = 0; i < openBrackets - closedBrackets; i++) repaired += "}";
1445
+ return repaired;
1446
+ }
1417
1447
  };
1418
1448
 
1419
1449
  // src/rag/Reranker.ts
@@ -2854,29 +2854,59 @@ var EntityExtractor = class {
2854
2854
  async extract(text) {
2855
2855
  const prompt = `
2856
2856
  Extract entities and relationships from the following text.
2857
- Format the output as JSON with two keys: "nodes" (array of {id, label, properties}) and "edges" (array of {source, target, type, properties}).
2858
- Use the same ID for the same entity.
2857
+ Format the output as a JSON object with exactly two keys: "nodes" and "edges".
2859
2858
 
2860
- IMPORTANT: Ensure all property values are valid JSON types (strings, numbers, booleans, or null).
2861
- DO NOT include mathematical expressions like "4.5/5" as numbers; use strings instead.
2859
+ Nodes: {id, label, properties}
2860
+ Edges: {source, target, type, properties}
2862
2861
 
2863
- Text:
2864
- "${text}"
2862
+ IMPORTANT:
2863
+ - Ensure all property values are simple JSON types (string, number, boolean).
2864
+ - Do not use mathematical expressions or complex nested objects in properties.
2865
+ - If no entities are found, return empty arrays.
2866
+ - RESPOND ONLY WITH THE JSON OBJECT.
2865
2867
 
2866
- Output JSON:
2868
+ Text to extract from:
2869
+ "${text}"
2867
2870
  `;
2868
2871
  const response = await this.llm.chat([
2869
- { role: "system", content: "You are an expert at knowledge graph extraction. Respond only with valid JSON." },
2872
+ { role: "system", content: "You are a precise knowledge graph extraction engine. You always output valid JSON and nothing else." },
2870
2873
  { role: "user", content: prompt }
2871
- ], "");
2874
+ ], "", { maxTokens: 4096, temperature: 0.1 });
2872
2875
  try {
2873
- const cleanJson = response.replace(/```json\n?|\n?```/g, "").trim();
2876
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
2877
+ const cleanJson = jsonMatch ? jsonMatch[0] : response.trim();
2874
2878
  return JSON.parse(cleanJson);
2875
2879
  } catch (e) {
2876
- console.warn("[EntityExtractor] Failed to parse LLM response as JSON:", response);
2880
+ try {
2881
+ const repaired = this.repairTruncatedJson(response);
2882
+ if (repaired) return JSON.parse(repaired);
2883
+ } catch (e2) {
2884
+ }
2885
+ console.warn(`[EntityExtractor] Failed to parse LLM response. Length: ${response.length} chars.`);
2886
+ console.warn("[EntityExtractor] Snippet:", response.substring(0, 100) + "...");
2877
2887
  return { nodes: [], edges: [] };
2878
2888
  }
2879
2889
  }
2890
+ /**
2891
+ * Attempts to fix JSON that was cut off mid-generation.
2892
+ * Strategy: Find the last valid element in an array and close the structure.
2893
+ */
2894
+ repairTruncatedJson(json) {
2895
+ let text = json.trim();
2896
+ const startIdx = text.indexOf("{");
2897
+ if (startIdx === -1) return null;
2898
+ text = text.substring(startIdx);
2899
+ const lastCompleteObjectIdx = text.lastIndexOf("}");
2900
+ if (lastCompleteObjectIdx === -1) return null;
2901
+ let repaired = text.substring(0, lastCompleteObjectIdx + 1);
2902
+ const openBrackets = (repaired.match(/\{/g) || []).length;
2903
+ const closedBrackets = (repaired.match(/\}/g) || []).length;
2904
+ const openSquares = (repaired.match(/\[/g) || []).length;
2905
+ const closedSquares = (repaired.match(/\]/g) || []).length;
2906
+ for (let i = 0; i < openSquares - closedSquares; i++) repaired += "]";
2907
+ for (let i = 0; i < openBrackets - closedBrackets; i++) repaired += "}";
2908
+ return repaired;
2909
+ }
2880
2910
  };
2881
2911
 
2882
2912
  // src/rag/Reranker.ts
@@ -4,7 +4,7 @@ import {
4
4
  createIngestHandler,
5
5
  createStreamHandler,
6
6
  createUploadHandler
7
- } from "../chunk-OJNAKSQ2.mjs";
7
+ } from "../chunk-6MLZHQZT.mjs";
8
8
  import "../chunk-YLTMFW4M.mjs";
9
9
  import "../chunk-X4TOT24V.mjs";
10
10
  export {
package/dist/server.js CHANGED
@@ -2936,29 +2936,59 @@ var EntityExtractor = class {
2936
2936
  async extract(text) {
2937
2937
  const prompt = `
2938
2938
  Extract entities and relationships from the following text.
2939
- Format the output as JSON with two keys: "nodes" (array of {id, label, properties}) and "edges" (array of {source, target, type, properties}).
2940
- Use the same ID for the same entity.
2939
+ Format the output as a JSON object with exactly two keys: "nodes" and "edges".
2941
2940
 
2942
- IMPORTANT: Ensure all property values are valid JSON types (strings, numbers, booleans, or null).
2943
- DO NOT include mathematical expressions like "4.5/5" as numbers; use strings instead.
2941
+ Nodes: {id, label, properties}
2942
+ Edges: {source, target, type, properties}
2944
2943
 
2945
- Text:
2946
- "${text}"
2944
+ IMPORTANT:
2945
+ - Ensure all property values are simple JSON types (string, number, boolean).
2946
+ - Do not use mathematical expressions or complex nested objects in properties.
2947
+ - If no entities are found, return empty arrays.
2948
+ - RESPOND ONLY WITH THE JSON OBJECT.
2947
2949
 
2948
- Output JSON:
2950
+ Text to extract from:
2951
+ "${text}"
2949
2952
  `;
2950
2953
  const response = await this.llm.chat([
2951
- { role: "system", content: "You are an expert at knowledge graph extraction. Respond only with valid JSON." },
2954
+ { role: "system", content: "You are a precise knowledge graph extraction engine. You always output valid JSON and nothing else." },
2952
2955
  { role: "user", content: prompt }
2953
- ], "");
2956
+ ], "", { maxTokens: 4096, temperature: 0.1 });
2954
2957
  try {
2955
- const cleanJson = response.replace(/```json\n?|\n?```/g, "").trim();
2958
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
2959
+ const cleanJson = jsonMatch ? jsonMatch[0] : response.trim();
2956
2960
  return JSON.parse(cleanJson);
2957
2961
  } catch (e) {
2958
- console.warn("[EntityExtractor] Failed to parse LLM response as JSON:", response);
2962
+ try {
2963
+ const repaired = this.repairTruncatedJson(response);
2964
+ if (repaired) return JSON.parse(repaired);
2965
+ } catch (e2) {
2966
+ }
2967
+ console.warn(`[EntityExtractor] Failed to parse LLM response. Length: ${response.length} chars.`);
2968
+ console.warn("[EntityExtractor] Snippet:", response.substring(0, 100) + "...");
2959
2969
  return { nodes: [], edges: [] };
2960
2970
  }
2961
2971
  }
2972
+ /**
2973
+ * Attempts to fix JSON that was cut off mid-generation.
2974
+ * Strategy: Find the last valid element in an array and close the structure.
2975
+ */
2976
+ repairTruncatedJson(json) {
2977
+ let text = json.trim();
2978
+ const startIdx = text.indexOf("{");
2979
+ if (startIdx === -1) return null;
2980
+ text = text.substring(startIdx);
2981
+ const lastCompleteObjectIdx = text.lastIndexOf("}");
2982
+ if (lastCompleteObjectIdx === -1) return null;
2983
+ let repaired = text.substring(0, lastCompleteObjectIdx + 1);
2984
+ const openBrackets = (repaired.match(/\{/g) || []).length;
2985
+ const closedBrackets = (repaired.match(/\}/g) || []).length;
2986
+ const openSquares = (repaired.match(/\[/g) || []).length;
2987
+ const closedSquares = (repaired.match(/\]/g) || []).length;
2988
+ for (let i = 0; i < openSquares - closedSquares; i++) repaired += "]";
2989
+ for (let i = 0; i < openBrackets - closedBrackets; i++) repaired += "}";
2990
+ return repaired;
2991
+ }
2962
2992
  };
2963
2993
 
2964
2994
  // src/rag/Reranker.ts
package/dist/server.mjs CHANGED
@@ -34,7 +34,7 @@ import {
34
34
  createIngestHandler,
35
35
  createUploadHandler,
36
36
  getRagConfig
37
- } from "./chunk-OJNAKSQ2.mjs";
37
+ } from "./chunk-6MLZHQZT.mjs";
38
38
  import "./chunk-YLTMFW4M.mjs";
39
39
  import {
40
40
  PineconeProvider
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retrivora-ai/rag-engine",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Retrivora AI is a plug-and-play AI engine for RAG chat experiences — generic vector DB + LLM provider, embeddable or standalone.",
5
5
  "author": "Abhinav Alkuchi",
6
6
  "license": "MIT",
@@ -17,30 +17,74 @@ export class EntityExtractor {
17
17
  async extract(text: string): Promise<{ nodes: GraphNode[]; edges: Edge[] }> {
18
18
  const prompt = `
19
19
  Extract entities and relationships from the following text.
20
- Format the output as JSON with two keys: "nodes" (array of {id, label, properties}) and "edges" (array of {source, target, type, properties}).
21
- Use the same ID for the same entity.
20
+ Format the output as a JSON object with exactly two keys: "nodes" and "edges".
22
21
 
23
- IMPORTANT: Ensure all property values are valid JSON types (strings, numbers, booleans, or null).
24
- DO NOT include mathematical expressions like "4.5/5" as numbers; use strings instead.
22
+ Nodes: {id, label, properties}
23
+ Edges: {source, target, type, properties}
25
24
 
26
- Text:
27
- "${text}"
25
+ IMPORTANT:
26
+ - Ensure all property values are simple JSON types (string, number, boolean).
27
+ - Do not use mathematical expressions or complex nested objects in properties.
28
+ - If no entities are found, return empty arrays.
29
+ - RESPOND ONLY WITH THE JSON OBJECT.
28
30
 
29
- Output JSON:
31
+ Text to extract from:
32
+ "${text}"
30
33
  `;
31
34
 
32
35
  const response = await this.llm.chat([
33
- { role: 'system', content: 'You are an expert at knowledge graph extraction. Respond only with valid JSON.' },
36
+ { role: 'system', content: 'You are a precise knowledge graph extraction engine. You always output valid JSON and nothing else.' },
34
37
  { role: 'user', content: prompt }
35
- ], '');
38
+ ], '', { maxTokens: 4096, temperature: 0.1 });
36
39
 
37
40
  try {
38
- // Clean up LLM response (sometimes it adds markdown blocks)
39
- const cleanJson = response.replace(/```json\n?|\n?```/g, '').trim();
41
+ // 1. Try to find the JSON block using a regex
42
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
43
+ const cleanJson = jsonMatch ? jsonMatch[0] : response.trim();
44
+
40
45
  return JSON.parse(cleanJson);
41
46
  } catch {
42
- console.warn('[EntityExtractor] Failed to parse LLM response as JSON:', response);
47
+ // 2. If parsing fails, try to repair truncated JSON
48
+ try {
49
+ const repaired = this.repairTruncatedJson(response);
50
+ if (repaired) return JSON.parse(repaired);
51
+ } catch { /* ignore repair failure */ }
52
+
53
+ console.warn(`[EntityExtractor] Failed to parse LLM response. Length: ${response.length} chars.`);
54
+ console.warn('[EntityExtractor] Snippet:', response.substring(0, 100) + '...');
43
55
  return { nodes: [], edges: [] };
44
56
  }
45
57
  }
58
+
59
+ /**
60
+ * Attempts to fix JSON that was cut off mid-generation.
61
+ * Strategy: Find the last valid element in an array and close the structure.
62
+ */
63
+ private repairTruncatedJson(json: string): string | null {
64
+ let text = json.trim();
65
+
66
+ // Find the first { and work from there
67
+ const startIdx = text.indexOf('{');
68
+ if (startIdx === -1) return null;
69
+ text = text.substring(startIdx);
70
+
71
+ // If it's truncated in an array like "nodes": [ ... , { ...
72
+ // We try to find the last complete object before the truncation
73
+ const lastCompleteObjectIdx = text.lastIndexOf('}');
74
+ if (lastCompleteObjectIdx === -1) return null;
75
+
76
+ // Truncate at the last complete object
77
+ let repaired = text.substring(0, lastCompleteObjectIdx + 1);
78
+
79
+ // Close any open structures (arrays or the main object)
80
+ const openBrackets = (repaired.match(/\{/g) || []).length;
81
+ const closedBrackets = (repaired.match(/\}/g) || []).length;
82
+ const openSquares = (repaired.match(/\[/g) || []).length;
83
+ const closedSquares = (repaired.match(/\]/g) || []).length;
84
+
85
+ for (let i = 0; i < openSquares - closedSquares; i++) repaired += ']';
86
+ for (let i = 0; i < openBrackets - closedBrackets; i++) repaired += '}';
87
+
88
+ return repaired;
89
+ }
46
90
  }