@retrivora-ai/rag-engine 1.0.6 → 1.0.7

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.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  MongoDBProvider
3
- } from "./chunk-73I6VWU3.mjs";
3
+ } from "./chunk-5AJ4XHLW.mjs";
4
4
  import "./chunk-IMP6FUCY.mjs";
5
5
  import "./chunk-X4TOT24V.mjs";
6
6
  export {
@@ -1098,7 +1098,7 @@ var ProviderRegistry = class {
1098
1098
  return PostgreSQLProvider;
1099
1099
  }
1100
1100
  case "mongodb": {
1101
- const { MongoDBProvider } = await import("./MongoDBProvider-BO2Y5DRR.mjs");
1101
+ const { MongoDBProvider } = await import("./MongoDBProvider-YNKC7EJ6.mjs");
1102
1102
  return MongoDBProvider;
1103
1103
  }
1104
1104
  case "milvus": {
@@ -1915,7 +1915,6 @@ var QueryProcessor = class {
1915
1915
  var _a, _b, _c, _d;
1916
1916
  if (!question.trim()) return [];
1917
1917
  const hints = /* @__PURE__ */ new Map();
1918
- const fieldsToSearch = [.../* @__PURE__ */ new Set([...this.COMMON_METADATA_FIELDS, ...validFields])];
1919
1918
  const addHint = (value, field) => {
1920
1919
  const normalizedValue = this.normalizeHintValue(value);
1921
1920
  if (!normalizedValue) return;
@@ -1946,17 +1945,18 @@ var QueryProcessor = class {
1946
1945
  if (name) addHint(name, "name");
1947
1946
  }
1948
1947
  }
1949
- if (fieldsToSearch.length > 0) {
1950
- for (const field of fieldsToSearch) {
1951
- const forwardPattern = new RegExp(`\\b${field}\\s*(?:is|are|:|of)?\\s+["']?([^"\\n?.!,]{2,60})["']?(?=[?.!,]|$)`, "gi");
1952
- for (const match of question.matchAll(forwardPattern)) {
1953
- const value = match[1];
1954
- if (value && !this.isLikelyPromptPhrase(value)) {
1955
- addHint(value, field);
1956
- }
1957
- }
1958
- const reversePattern = new RegExp(`\\b([^"\\n?.!,\\s]{2,60})\\s+${field}\\b`, "gi");
1959
- for (const match of question.matchAll(reversePattern)) {
1948
+ const genericPattern = /\b([a-z][a-z0-9_]{1,30})\s*[:=]\s*["']?([^"'\n?.!,]{1,60})["']?/gi;
1949
+ for (const match of question.matchAll(genericPattern)) {
1950
+ const field = match[1];
1951
+ const value = match[2];
1952
+ if (field && !this.isLikelyPromptPhrase(field)) {
1953
+ addHint(value, field);
1954
+ }
1955
+ }
1956
+ if (validFields.length > 0) {
1957
+ for (const field of validFields) {
1958
+ const pattern = new RegExp(`\\b${field}\\s*(?:is|are|:|of)?\\s+["']?([^"\\n?.!,]{1,60})["']?(?=[?.!,]|$)`, "gi");
1959
+ for (const match of question.matchAll(pattern)) {
1960
1960
  const value = match[1];
1961
1961
  if (value && !this.isLikelyPromptPhrase(value)) {
1962
1962
  addHint(value, field);
@@ -2032,28 +2032,6 @@ var QueryProcessor = class {
2032
2032
  return filter;
2033
2033
  }
2034
2034
  };
2035
- QueryProcessor.COMMON_METADATA_FIELDS = [
2036
- "category",
2037
- "type",
2038
- "brand",
2039
- "status",
2040
- "priority",
2041
- "id",
2042
- "name",
2043
- "email",
2044
- "phone",
2045
- "price",
2046
- "rating",
2047
- "color",
2048
- "size",
2049
- "material",
2050
- "sku",
2051
- "role",
2052
- "department",
2053
- "location",
2054
- "tag",
2055
- "label"
2056
- ];
2057
2035
 
2058
2036
  // src/core/Pipeline.ts
2059
2037
  var LRUEmbeddingCache = class {
@@ -118,6 +118,18 @@ var MongoDBProvider = class extends BaseVectorProvider {
118
118
  }
119
119
  async query(vector, topK, namespace, filter) {
120
120
  const publicFilter = this.sanitizeFilter(filter);
121
+ const vectorSearchFilter = {};
122
+ const matchFilter = {};
123
+ if (namespace) {
124
+ vectorSearchFilter.namespace = namespace;
125
+ }
126
+ for (const [key, value] of Object.entries(publicFilter)) {
127
+ if (key === "namespace") {
128
+ vectorSearchFilter.namespace = value;
129
+ } else {
130
+ matchFilter[key] = value;
131
+ }
132
+ }
121
133
  const pipeline = [
122
134
  {
123
135
  $vectorSearch: __spreadValues({
@@ -125,9 +137,15 @@ var MongoDBProvider = class extends BaseVectorProvider {
125
137
  path: this.embeddingKey,
126
138
  queryVector: vector,
127
139
  numCandidates: this.config.options.numCandidates || Math.max(topK * 20, 200),
128
- limit: topK
129
- }, Object.keys(publicFilter).length > 0 || namespace ? { filter: __spreadValues(__spreadValues({}, publicFilter), namespace ? { namespace } : {}) } : {})
130
- },
140
+ limit: topK * 2
141
+ }, Object.keys(vectorSearchFilter).length > 0 ? { filter: vectorSearchFilter } : {})
142
+ }
143
+ ];
144
+ if (Object.keys(matchFilter).length > 0) {
145
+ pipeline.push({ $match: matchFilter });
146
+ }
147
+ pipeline.push(
148
+ { $limit: topK },
131
149
  {
132
150
  $project: {
133
151
  _id: 1,
@@ -137,7 +155,7 @@ var MongoDBProvider = class extends BaseVectorProvider {
137
155
  score: { $meta: "vectorSearchScore" }
138
156
  }
139
157
  }
140
- ];
158
+ );
141
159
  const results = await this.collection.aggregate(pipeline).toArray();
142
160
  return results.map((res) => ({
143
161
  id: res._id,
@@ -650,6 +650,18 @@ var init_MongoDBProvider = __esm({
650
650
  }
651
651
  async query(vector, topK, namespace, filter) {
652
652
  const publicFilter = this.sanitizeFilter(filter);
653
+ const vectorSearchFilter = {};
654
+ const matchFilter = {};
655
+ if (namespace) {
656
+ vectorSearchFilter.namespace = namespace;
657
+ }
658
+ for (const [key, value] of Object.entries(publicFilter)) {
659
+ if (key === "namespace") {
660
+ vectorSearchFilter.namespace = value;
661
+ } else {
662
+ matchFilter[key] = value;
663
+ }
664
+ }
653
665
  const pipeline = [
654
666
  {
655
667
  $vectorSearch: __spreadValues({
@@ -657,9 +669,15 @@ var init_MongoDBProvider = __esm({
657
669
  path: this.embeddingKey,
658
670
  queryVector: vector,
659
671
  numCandidates: this.config.options.numCandidates || Math.max(topK * 20, 200),
660
- limit: topK
661
- }, Object.keys(publicFilter).length > 0 || namespace ? { filter: __spreadValues(__spreadValues({}, publicFilter), namespace ? { namespace } : {}) } : {})
662
- },
672
+ limit: topK * 2
673
+ }, Object.keys(vectorSearchFilter).length > 0 ? { filter: vectorSearchFilter } : {})
674
+ }
675
+ ];
676
+ if (Object.keys(matchFilter).length > 0) {
677
+ pipeline.push({ $match: matchFilter });
678
+ }
679
+ pipeline.push(
680
+ { $limit: topK },
663
681
  {
664
682
  $project: {
665
683
  _id: 1,
@@ -669,7 +687,7 @@ var init_MongoDBProvider = __esm({
669
687
  score: { $meta: "vectorSearchScore" }
670
688
  }
671
689
  }
672
- ];
690
+ );
673
691
  const results = await this.collection.aggregate(pipeline).toArray();
674
692
  return results.map((res) => ({
675
693
  id: res._id,
@@ -3373,7 +3391,6 @@ var QueryProcessor = class {
3373
3391
  var _a, _b, _c, _d;
3374
3392
  if (!question.trim()) return [];
3375
3393
  const hints = /* @__PURE__ */ new Map();
3376
- const fieldsToSearch = [.../* @__PURE__ */ new Set([...this.COMMON_METADATA_FIELDS, ...validFields])];
3377
3394
  const addHint = (value, field) => {
3378
3395
  const normalizedValue = this.normalizeHintValue(value);
3379
3396
  if (!normalizedValue) return;
@@ -3404,17 +3421,18 @@ var QueryProcessor = class {
3404
3421
  if (name) addHint(name, "name");
3405
3422
  }
3406
3423
  }
3407
- if (fieldsToSearch.length > 0) {
3408
- for (const field of fieldsToSearch) {
3409
- const forwardPattern = new RegExp(`\\b${field}\\s*(?:is|are|:|of)?\\s+["']?([^"\\n?.!,]{2,60})["']?(?=[?.!,]|$)`, "gi");
3410
- for (const match of question.matchAll(forwardPattern)) {
3411
- const value = match[1];
3412
- if (value && !this.isLikelyPromptPhrase(value)) {
3413
- addHint(value, field);
3414
- }
3415
- }
3416
- const reversePattern = new RegExp(`\\b([^"\\n?.!,\\s]{2,60})\\s+${field}\\b`, "gi");
3417
- for (const match of question.matchAll(reversePattern)) {
3424
+ const genericPattern = /\b([a-z][a-z0-9_]{1,30})\s*[:=]\s*["']?([^"'\n?.!,]{1,60})["']?/gi;
3425
+ for (const match of question.matchAll(genericPattern)) {
3426
+ const field = match[1];
3427
+ const value = match[2];
3428
+ if (field && !this.isLikelyPromptPhrase(field)) {
3429
+ addHint(value, field);
3430
+ }
3431
+ }
3432
+ if (validFields.length > 0) {
3433
+ for (const field of validFields) {
3434
+ const pattern = new RegExp(`\\b${field}\\s*(?:is|are|:|of)?\\s+["']?([^"\\n?.!,]{1,60})["']?(?=[?.!,]|$)`, "gi");
3435
+ for (const match of question.matchAll(pattern)) {
3418
3436
  const value = match[1];
3419
3437
  if (value && !this.isLikelyPromptPhrase(value)) {
3420
3438
  addHint(value, field);
@@ -3490,28 +3508,6 @@ var QueryProcessor = class {
3490
3508
  return filter;
3491
3509
  }
3492
3510
  };
3493
- QueryProcessor.COMMON_METADATA_FIELDS = [
3494
- "category",
3495
- "type",
3496
- "brand",
3497
- "status",
3498
- "priority",
3499
- "id",
3500
- "name",
3501
- "email",
3502
- "phone",
3503
- "price",
3504
- "rating",
3505
- "color",
3506
- "size",
3507
- "material",
3508
- "sku",
3509
- "role",
3510
- "department",
3511
- "location",
3512
- "tag",
3513
- "label"
3514
- ];
3515
3511
 
3516
3512
  // src/core/Pipeline.ts
3517
3513
  var LRUEmbeddingCache = class {
@@ -8,7 +8,7 @@ import {
8
8
  sseFrame,
9
9
  sseMetaFrame,
10
10
  sseTextFrame
11
- } from "../chunk-ZCDJSGUW.mjs";
11
+ } from "../chunk-3GKA3PJF.mjs";
12
12
  import "../chunk-YLTMFW4M.mjs";
13
13
  import "../chunk-X4TOT24V.mjs";
14
14
  export {
package/dist/server.js CHANGED
@@ -662,6 +662,18 @@ var init_MongoDBProvider = __esm({
662
662
  }
663
663
  async query(vector, topK, namespace, filter) {
664
664
  const publicFilter = this.sanitizeFilter(filter);
665
+ const vectorSearchFilter = {};
666
+ const matchFilter = {};
667
+ if (namespace) {
668
+ vectorSearchFilter.namespace = namespace;
669
+ }
670
+ for (const [key, value] of Object.entries(publicFilter)) {
671
+ if (key === "namespace") {
672
+ vectorSearchFilter.namespace = value;
673
+ } else {
674
+ matchFilter[key] = value;
675
+ }
676
+ }
665
677
  const pipeline = [
666
678
  {
667
679
  $vectorSearch: __spreadValues({
@@ -669,9 +681,15 @@ var init_MongoDBProvider = __esm({
669
681
  path: this.embeddingKey,
670
682
  queryVector: vector,
671
683
  numCandidates: this.config.options.numCandidates || Math.max(topK * 20, 200),
672
- limit: topK
673
- }, Object.keys(publicFilter).length > 0 || namespace ? { filter: __spreadValues(__spreadValues({}, publicFilter), namespace ? { namespace } : {}) } : {})
674
- },
684
+ limit: topK * 2
685
+ }, Object.keys(vectorSearchFilter).length > 0 ? { filter: vectorSearchFilter } : {})
686
+ }
687
+ ];
688
+ if (Object.keys(matchFilter).length > 0) {
689
+ pipeline.push({ $match: matchFilter });
690
+ }
691
+ pipeline.push(
692
+ { $limit: topK },
675
693
  {
676
694
  $project: {
677
695
  _id: 1,
@@ -681,7 +699,7 @@ var init_MongoDBProvider = __esm({
681
699
  score: { $meta: "vectorSearchScore" }
682
700
  }
683
701
  }
684
- ];
702
+ );
685
703
  const results = await this.collection.aggregate(pipeline).toArray();
686
704
  return results.map((res) => ({
687
705
  id: res._id,
@@ -3466,7 +3484,6 @@ var QueryProcessor = class {
3466
3484
  var _a, _b, _c, _d;
3467
3485
  if (!question.trim()) return [];
3468
3486
  const hints = /* @__PURE__ */ new Map();
3469
- const fieldsToSearch = [.../* @__PURE__ */ new Set([...this.COMMON_METADATA_FIELDS, ...validFields])];
3470
3487
  const addHint = (value, field) => {
3471
3488
  const normalizedValue = this.normalizeHintValue(value);
3472
3489
  if (!normalizedValue) return;
@@ -3497,17 +3514,18 @@ var QueryProcessor = class {
3497
3514
  if (name) addHint(name, "name");
3498
3515
  }
3499
3516
  }
3500
- if (fieldsToSearch.length > 0) {
3501
- for (const field of fieldsToSearch) {
3502
- const forwardPattern = new RegExp(`\\b${field}\\s*(?:is|are|:|of)?\\s+["']?([^"\\n?.!,]{2,60})["']?(?=[?.!,]|$)`, "gi");
3503
- for (const match of question.matchAll(forwardPattern)) {
3504
- const value = match[1];
3505
- if (value && !this.isLikelyPromptPhrase(value)) {
3506
- addHint(value, field);
3507
- }
3508
- }
3509
- const reversePattern = new RegExp(`\\b([^"\\n?.!,\\s]{2,60})\\s+${field}\\b`, "gi");
3510
- for (const match of question.matchAll(reversePattern)) {
3517
+ const genericPattern = /\b([a-z][a-z0-9_]{1,30})\s*[:=]\s*["']?([^"'\n?.!,]{1,60})["']?/gi;
3518
+ for (const match of question.matchAll(genericPattern)) {
3519
+ const field = match[1];
3520
+ const value = match[2];
3521
+ if (field && !this.isLikelyPromptPhrase(field)) {
3522
+ addHint(value, field);
3523
+ }
3524
+ }
3525
+ if (validFields.length > 0) {
3526
+ for (const field of validFields) {
3527
+ const pattern = new RegExp(`\\b${field}\\s*(?:is|are|:|of)?\\s+["']?([^"\\n?.!,]{1,60})["']?(?=[?.!,]|$)`, "gi");
3528
+ for (const match of question.matchAll(pattern)) {
3511
3529
  const value = match[1];
3512
3530
  if (value && !this.isLikelyPromptPhrase(value)) {
3513
3531
  addHint(value, field);
@@ -3583,28 +3601,6 @@ var QueryProcessor = class {
3583
3601
  return filter;
3584
3602
  }
3585
3603
  };
3586
- QueryProcessor.COMMON_METADATA_FIELDS = [
3587
- "category",
3588
- "type",
3589
- "brand",
3590
- "status",
3591
- "priority",
3592
- "id",
3593
- "name",
3594
- "email",
3595
- "phone",
3596
- "price",
3597
- "rating",
3598
- "color",
3599
- "size",
3600
- "material",
3601
- "sku",
3602
- "role",
3603
- "department",
3604
- "location",
3605
- "tag",
3606
- "label"
3607
- ];
3608
3604
 
3609
3605
  // src/core/Pipeline.ts
3610
3606
  var LRUEmbeddingCache = class {
package/dist/server.mjs CHANGED
@@ -40,7 +40,7 @@ import {
40
40
  sseFrame,
41
41
  sseMetaFrame,
42
42
  sseTextFrame
43
- } from "./chunk-ZCDJSGUW.mjs";
43
+ } from "./chunk-3GKA3PJF.mjs";
44
44
  import "./chunk-YLTMFW4M.mjs";
45
45
  import {
46
46
  PineconeProvider
@@ -50,7 +50,7 @@ import {
50
50
  } from "./chunk-FLOSGE6A.mjs";
51
51
  import {
52
52
  MongoDBProvider
53
- } from "./chunk-73I6VWU3.mjs";
53
+ } from "./chunk-5AJ4XHLW.mjs";
54
54
  import {
55
55
  MilvusProvider
56
56
  } from "./chunk-U55XRW3U.mjs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retrivora-ai/rag-engine",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
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",
@@ -34,11 +34,6 @@ export class QueryProcessor {
34
34
  return /^(what|which|who|where|when|why|how|the|is|are|was|were|in|on|at|by|for|with|about|a|an|to|of)\b/i.test(value.trim());
35
35
  }
36
36
 
37
- private static readonly COMMON_METADATA_FIELDS = [
38
- 'category', 'type', 'brand', 'status', 'priority', 'id', 'name',
39
- 'email', 'phone', 'price', 'rating', 'color', 'size', 'material',
40
- 'sku', 'role', 'department', 'location', 'tag', 'label'
41
- ];
42
37
 
43
38
  /**
44
39
  * Scans a natural language question for potential metadata hints and keywords.
@@ -49,7 +44,6 @@ export class QueryProcessor {
49
44
  if (!question.trim()) return [];
50
45
 
51
46
  const hints = new Map<string, QueryFieldHint>();
52
- const fieldsToSearch = [...new Set([...this.COMMON_METADATA_FIELDS, ...validFields])];
53
47
 
54
48
  const addHint = (value: string, field?: string) => {
55
49
  const normalizedValue = this.normalizeHintValue(value);
@@ -98,21 +92,22 @@ export class QueryProcessor {
98
92
  }
99
93
 
100
94
  // 4. Dynamic Schema-driven patterns
101
- // We look for common metadata fields (and any user-defined ones) in natural language.
102
- if (fieldsToSearch.length > 0) {
103
- for (const field of fieldsToSearch) {
104
- // Pattern 1: "[field] is [value]", "[field]: [value]", "[field] of [value]"
105
- const forwardPattern = new RegExp(`\\b${field}\\s*(?:is|are|:|of)?\\s+["']?([^"\\n?.!,]{2,60})["']?(?=[?.!,]|$)`, 'gi');
106
- for (const match of question.matchAll(forwardPattern)) {
107
- const value = match[1];
108
- if (value && !this.isLikelyPromptPhrase(value)) {
109
- addHint(value, field);
110
- }
111
- }
95
+ // We look for any word-like key followed by a colon or equals.
96
+ const genericPattern = /\b([a-z][a-z0-9_]{1,30})\s*[:=]\s*["']?([^"'\n?.!,]{1,60})["']?/gi;
97
+ for (const match of question.matchAll(genericPattern)) {
98
+ const field = match[1];
99
+ const value = match[2];
100
+ if (field && !this.isLikelyPromptPhrase(field)) {
101
+ addHint(value, field);
102
+ }
103
+ }
112
104
 
113
- // Pattern 2: "[value] [field]" (e.g. "blue color", "electronics category")
114
- const reversePattern = new RegExp(`\\b([^"\\n?.!,\\s]{2,60})\\s+${field}\\b`, 'gi');
115
- for (const match of question.matchAll(reversePattern)) {
105
+ // 5. Explicitly requested fields (if any)
106
+ if (validFields.length > 0) {
107
+ for (const field of validFields) {
108
+ // More aggressive pattern for explicitly allowed fields: "[field] [value]"
109
+ const pattern = new RegExp(`\\b${field}\\s*(?:is|are|:|of)?\\s+["']?([^"\\n?.!,]{1,60})["']?(?=[?.!,]|$)`, 'gi');
110
+ for (const match of question.matchAll(pattern)) {
116
111
  const value = match[1];
117
112
  if (value && !this.isLikelyPromptPhrase(value)) {
118
113
  addHint(value, field);
@@ -139,6 +139,24 @@ export class MongoDBProvider extends BaseVectorProvider {
139
139
 
140
140
  async query(vector: number[], topK: number, namespace?: string, filter?: Record<string, unknown>): Promise<VectorMatch[]> {
141
141
  const publicFilter = this.sanitizeFilter(filter);
142
+
143
+ // Split filters: only 'namespace' is safe for the $vectorSearch 'filter' argument
144
+ // unless explicitly indexed. Moving others to a subsequent $match stage.
145
+ const vectorSearchFilter: Record<string, unknown> = {};
146
+ const matchFilter: Record<string, unknown> = {};
147
+
148
+ if (namespace) {
149
+ vectorSearchFilter.namespace = namespace;
150
+ }
151
+
152
+ for (const [key, value] of Object.entries(publicFilter)) {
153
+ if (key === 'namespace') {
154
+ vectorSearchFilter.namespace = value;
155
+ } else {
156
+ matchFilter[key] = value;
157
+ }
158
+ }
159
+
142
160
  const pipeline: Record<string, unknown>[] = [
143
161
  {
144
162
  $vectorSearch: {
@@ -146,12 +164,20 @@ export class MongoDBProvider extends BaseVectorProvider {
146
164
  path: this.embeddingKey,
147
165
  queryVector: vector,
148
166
  numCandidates: (this.config.options.numCandidates as number) || Math.max(topK * 20, 200),
149
- limit: topK,
150
- ...(Object.keys(publicFilter).length > 0 || namespace
151
- ? { filter: { ...publicFilter, ...(namespace ? { namespace } : {}) } }
152
- : {}),
167
+ limit: topK * 2, // Increase limit slightly to account for post-filtering
168
+ ...(Object.keys(vectorSearchFilter).length > 0 ? { filter: vectorSearchFilter } : {}),
153
169
  },
154
170
  },
171
+ ];
172
+
173
+ // Add post-filtering stage if there are additional filters
174
+ if (Object.keys(matchFilter).length > 0) {
175
+ pipeline.push({ $match: matchFilter });
176
+ }
177
+
178
+ // Final limit and projection
179
+ pipeline.push(
180
+ { $limit: topK },
155
181
  {
156
182
  $project: {
157
183
  _id: 1,
@@ -160,8 +186,8 @@ export class MongoDBProvider extends BaseVectorProvider {
160
186
  namespace: 1,
161
187
  score: { $meta: 'vectorSearchScore' },
162
188
  },
163
- },
164
- ];
189
+ }
190
+ );
165
191
 
166
192
  const results = await this.collection!.aggregate(pipeline).toArray();
167
193