@retrivora-ai/rag-engine 0.2.3 → 0.2.5

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.
@@ -1640,7 +1640,7 @@ var Pipeline = class {
1640
1640
  const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0;
1641
1641
  try {
1642
1642
  const queryVector = await this.embeddingProvider.embed(question, { taskType: "query" });
1643
- const rawMatches = await this.vectorDB.query(queryVector, topK, ns);
1643
+ const rawMatches = await this.vectorDB.query(queryVector, topK, ns, { __queryText: question });
1644
1644
  const sources = rawMatches.filter((m) => m.score >= scoreThreshold);
1645
1645
  const context = sources.length ? sources.map((m, i) => `[Source ${i + 1}]
1646
1646
  ${m.content}`).join("\n\n---\n\n") : "No relevant context found.";
@@ -2750,7 +2750,7 @@ var Pipeline = class {
2750
2750
  const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0;
2751
2751
  try {
2752
2752
  const queryVector = await this.embeddingProvider.embed(question, { taskType: "query" });
2753
- const rawMatches = await this.vectorDB.query(queryVector, topK, ns);
2753
+ const rawMatches = await this.vectorDB.query(queryVector, topK, ns, { __queryText: question });
2754
2754
  const sources = rawMatches.filter((m) => m.score >= scoreThreshold);
2755
2755
  const context = sources.length ? sources.map((m, i) => `[Source ${i + 1}]
2756
2756
  ${m.content}`).join("\n\n---\n\n") : "No relevant context found.";
@@ -3,7 +3,7 @@ import {
3
3
  createHealthHandler,
4
4
  createIngestHandler,
5
5
  createUploadHandler
6
- } from "../chunk-K53N7SEE.mjs";
6
+ } from "../chunk-7K4KXB6G.mjs";
7
7
  import "../chunk-EDLTMSNY.mjs";
8
8
  import "../chunk-FWCSY2DS.mjs";
9
9
  export {
package/dist/server.d.mts CHANGED
@@ -720,8 +720,7 @@ declare class MultiTablePostgresProvider extends BaseVectorProvider {
720
720
  /**
721
721
  * Query all configured tables and merge results, sorted by cosine similarity score.
722
722
  */
723
- query(vector: number[], topK: number, _namespace?: string, // eslint-disable-line @typescript-eslint/no-unused-vars
724
- _filter?: Record<string, unknown>): Promise<VectorMatch[]>;
723
+ query(vector: number[], topK: number, _namespace?: string, _filter?: Record<string, unknown>): Promise<VectorMatch[]>;
725
724
  delete(_id: string | number, _namespace?: string): Promise<void>;
726
725
  deleteNamespace(_namespace: string): Promise<void>;
727
726
  ping(): Promise<boolean>;
package/dist/server.d.ts CHANGED
@@ -720,8 +720,7 @@ declare class MultiTablePostgresProvider extends BaseVectorProvider {
720
720
  /**
721
721
  * Query all configured tables and merge results, sorted by cosine similarity score.
722
722
  */
723
- query(vector: number[], topK: number, _namespace?: string, // eslint-disable-line @typescript-eslint/no-unused-vars
724
- _filter?: Record<string, unknown>): Promise<VectorMatch[]>;
723
+ query(vector: number[], topK: number, _namespace?: string, _filter?: Record<string, unknown>): Promise<VectorMatch[]>;
725
724
  delete(_id: string | number, _namespace?: string): Promise<void>;
726
725
  deleteNamespace(_namespace: string): Promise<void>;
727
726
  ping(): Promise<boolean>;
package/dist/server.js CHANGED
@@ -2839,7 +2839,7 @@ var Pipeline = class {
2839
2839
  const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0;
2840
2840
  try {
2841
2841
  const queryVector = await this.embeddingProvider.embed(question, { taskType: "query" });
2842
- const rawMatches = await this.vectorDB.query(queryVector, topK, ns);
2842
+ const rawMatches = await this.vectorDB.query(queryVector, topK, ns, { __queryText: question });
2843
2843
  const sources = rawMatches.filter((m) => m.score >= scoreThreshold);
2844
2844
  const context = sources.length ? sources.map((m, i) => `[Source ${i + 1}]
2845
2845
  ${m.content}`).join("\n\n---\n\n") : "No relevant context found.";
@@ -3763,50 +3763,76 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
3763
3763
  * Query all configured tables and merge results, sorted by cosine similarity score.
3764
3764
  */
3765
3765
  async query(vector, topK, _namespace, _filter) {
3766
- var _b, _c, _d;
3766
+ var _a, _b, _c;
3767
3767
  if (!this.pool) {
3768
3768
  throw new Error("[MultiTablePostgresProvider] Provider not initialized. Call initialize() first.");
3769
3769
  }
3770
3770
  const vectorLiteral = `[${vector.join(",")}]`;
3771
3771
  const allResults = [];
3772
3772
  console.log(`[MultiTablePostgresProvider] --- Starting Multi-Table Search ---`);
3773
- for (const table of this.tables) {
3773
+ const queryText = _filter == null ? void 0 : _filter.__queryText;
3774
+ const queryPromises = this.tables.map(async (table) => {
3774
3775
  try {
3775
- const result = await this.pool.query(
3776
- `SELECT *,
3777
- (1 - (embedding <=> $1::vector)) AS vector_score
3778
- FROM "${table}"
3779
- ORDER BY vector_score DESC
3780
- LIMIT 50`,
3781
- [vectorLiteral]
3782
- );
3776
+ let sqlQuery = "";
3777
+ let params = [];
3778
+ if (queryText) {
3779
+ sqlQuery = `
3780
+ SELECT *,
3781
+ (1 - (embedding <=> $1::vector)) AS vector_score,
3782
+ ts_rank(to_tsvector('english', t.*::text), plainto_tsquery('english', $2)) AS keyword_score,
3783
+ ((1 - (embedding <=> $1::vector)) + (ts_rank(to_tsvector('english', t.*::text), plainto_tsquery('english', $2)) * 2.0)) AS hybrid_score
3784
+ FROM "${table}" t
3785
+ ORDER BY hybrid_score DESC
3786
+ LIMIT 50
3787
+ `;
3788
+ params = [vectorLiteral, queryText];
3789
+ } else {
3790
+ sqlQuery = `
3791
+ SELECT *,
3792
+ (1 - (embedding <=> $1::vector)) AS hybrid_score
3793
+ FROM "${table}" t
3794
+ ORDER BY hybrid_score DESC
3795
+ LIMIT 50
3796
+ `;
3797
+ params = [vectorLiteral];
3798
+ }
3799
+ const result = await this.pool.query(sqlQuery, params);
3783
3800
  if (result.rowCount && result.rowCount > 0) {
3784
- console.log(` \u2705 Table "${table}": Found ${result.rowCount} potential matches. Top score: ${result.rows[0].vector_score.toFixed(4)}`);
3801
+ console.log(` \u2705 Table "${table}": Found ${result.rowCount} potential matches. Top score: ${result.rows[0].hybrid_score.toFixed(4)}`);
3785
3802
  } else {
3786
3803
  console.log(` \u26AA Table "${table}": No relevant matches found.`);
3787
3804
  }
3805
+ const tableResults = [];
3788
3806
  for (const row of result.rows) {
3789
- const _a = row, { vector_score, id } = _a, rest = __objRest(_a, ["vector_score", "id"]);
3807
+ const _a2 = row, { hybrid_score, id } = _a2, rest = __objRest(_a2, ["hybrid_score", "id"]);
3790
3808
  delete rest.embedding;
3809
+ delete rest.vector_score;
3810
+ delete rest.keyword_score;
3791
3811
  const content = `[TYPE: ${table.replace(/s$/, "").toUpperCase()}]
3792
3812
  ` + Object.entries(rest).filter(([k, v]) => v !== null && typeof v !== "object" && k !== "id").map(([k, v]) => `${k}: ${v}`).join("\n");
3793
- allResults.push({
3813
+ tableResults.push({
3794
3814
  id: `${table}-${id}`,
3795
- score: parseFloat(String(vector_score)),
3815
+ score: parseFloat(String(hybrid_score)),
3796
3816
  content,
3797
3817
  metadata: __spreadProps(__spreadValues({}, rest), { source_table: table })
3798
3818
  });
3799
3819
  }
3820
+ return tableResults;
3800
3821
  } catch (err) {
3801
3822
  console.error(
3802
3823
  `[MultiTablePostgresProvider] Error querying table "${table}":`,
3803
3824
  err.message
3804
3825
  );
3826
+ return [];
3805
3827
  }
3828
+ });
3829
+ const resultsArray = await Promise.all(queryPromises);
3830
+ for (const tableResults of resultsArray) {
3831
+ allResults.push(...tableResults);
3806
3832
  }
3807
3833
  const resultsByTable = {};
3808
3834
  for (const res of allResults) {
3809
- const table = (_b = res.metadata) == null ? void 0 : _b.source_table;
3835
+ const table = (_a = res.metadata) == null ? void 0 : _a.source_table;
3810
3836
  if (!resultsByTable[table]) resultsByTable[table] = [];
3811
3837
  resultsByTable[table].push(res);
3812
3838
  }
@@ -3818,7 +3844,7 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
3818
3844
  const finalSorted = balancedResults.sort((a, b) => b.score - a.score);
3819
3845
  if (finalSorted.length > 0) {
3820
3846
  console.log(`[MultiTablePostgresProvider] --- Search Complete ---`);
3821
- console.log(`[MultiTablePostgresProvider] Final top match from "${(_d = (_c = finalSorted[0].metadata) == null ? void 0 : _c.source_table) != null ? _d : "unknown"}" with score ${finalSorted[0].score.toFixed(4)}`);
3847
+ console.log(`[MultiTablePostgresProvider] Final top match from "${(_c = (_b = finalSorted[0].metadata) == null ? void 0 : _b.source_table) != null ? _c : "unknown"}" with score ${finalSorted[0].score.toFixed(4)}`);
3822
3848
  }
3823
3849
  return finalSorted.slice(0, Math.max(topK, 15));
3824
3850
  }
package/dist/server.mjs CHANGED
@@ -34,7 +34,7 @@ import {
34
34
  createIngestHandler,
35
35
  createUploadHandler,
36
36
  getRagConfig
37
- } from "./chunk-K53N7SEE.mjs";
37
+ } from "./chunk-7K4KXB6G.mjs";
38
38
  import "./chunk-EDLTMSNY.mjs";
39
39
  import {
40
40
  PineconeProvider
@@ -406,50 +406,76 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
406
406
  * Query all configured tables and merge results, sorted by cosine similarity score.
407
407
  */
408
408
  async query(vector, topK, _namespace, _filter) {
409
- var _b, _c, _d;
409
+ var _a, _b, _c;
410
410
  if (!this.pool) {
411
411
  throw new Error("[MultiTablePostgresProvider] Provider not initialized. Call initialize() first.");
412
412
  }
413
413
  const vectorLiteral = `[${vector.join(",")}]`;
414
414
  const allResults = [];
415
415
  console.log(`[MultiTablePostgresProvider] --- Starting Multi-Table Search ---`);
416
- for (const table of this.tables) {
416
+ const queryText = _filter == null ? void 0 : _filter.__queryText;
417
+ const queryPromises = this.tables.map(async (table) => {
417
418
  try {
418
- const result = await this.pool.query(
419
- `SELECT *,
420
- (1 - (embedding <=> $1::vector)) AS vector_score
421
- FROM "${table}"
422
- ORDER BY vector_score DESC
423
- LIMIT 50`,
424
- [vectorLiteral]
425
- );
419
+ let sqlQuery = "";
420
+ let params = [];
421
+ if (queryText) {
422
+ sqlQuery = `
423
+ SELECT *,
424
+ (1 - (embedding <=> $1::vector)) AS vector_score,
425
+ ts_rank(to_tsvector('english', t.*::text), plainto_tsquery('english', $2)) AS keyword_score,
426
+ ((1 - (embedding <=> $1::vector)) + (ts_rank(to_tsvector('english', t.*::text), plainto_tsquery('english', $2)) * 2.0)) AS hybrid_score
427
+ FROM "${table}" t
428
+ ORDER BY hybrid_score DESC
429
+ LIMIT 50
430
+ `;
431
+ params = [vectorLiteral, queryText];
432
+ } else {
433
+ sqlQuery = `
434
+ SELECT *,
435
+ (1 - (embedding <=> $1::vector)) AS hybrid_score
436
+ FROM "${table}" t
437
+ ORDER BY hybrid_score DESC
438
+ LIMIT 50
439
+ `;
440
+ params = [vectorLiteral];
441
+ }
442
+ const result = await this.pool.query(sqlQuery, params);
426
443
  if (result.rowCount && result.rowCount > 0) {
427
- console.log(` \u2705 Table "${table}": Found ${result.rowCount} potential matches. Top score: ${result.rows[0].vector_score.toFixed(4)}`);
444
+ console.log(` \u2705 Table "${table}": Found ${result.rowCount} potential matches. Top score: ${result.rows[0].hybrid_score.toFixed(4)}`);
428
445
  } else {
429
446
  console.log(` \u26AA Table "${table}": No relevant matches found.`);
430
447
  }
448
+ const tableResults = [];
431
449
  for (const row of result.rows) {
432
- const _a = row, { vector_score, id } = _a, rest = __objRest(_a, ["vector_score", "id"]);
450
+ const _a2 = row, { hybrid_score, id } = _a2, rest = __objRest(_a2, ["hybrid_score", "id"]);
433
451
  delete rest.embedding;
452
+ delete rest.vector_score;
453
+ delete rest.keyword_score;
434
454
  const content = `[TYPE: ${table.replace(/s$/, "").toUpperCase()}]
435
455
  ` + Object.entries(rest).filter(([k, v]) => v !== null && typeof v !== "object" && k !== "id").map(([k, v]) => `${k}: ${v}`).join("\n");
436
- allResults.push({
456
+ tableResults.push({
437
457
  id: `${table}-${id}`,
438
- score: parseFloat(String(vector_score)),
458
+ score: parseFloat(String(hybrid_score)),
439
459
  content,
440
460
  metadata: __spreadProps(__spreadValues({}, rest), { source_table: table })
441
461
  });
442
462
  }
463
+ return tableResults;
443
464
  } catch (err) {
444
465
  console.error(
445
466
  `[MultiTablePostgresProvider] Error querying table "${table}":`,
446
467
  err.message
447
468
  );
469
+ return [];
448
470
  }
471
+ });
472
+ const resultsArray = await Promise.all(queryPromises);
473
+ for (const tableResults of resultsArray) {
474
+ allResults.push(...tableResults);
449
475
  }
450
476
  const resultsByTable = {};
451
477
  for (const res of allResults) {
452
- const table = (_b = res.metadata) == null ? void 0 : _b.source_table;
478
+ const table = (_a = res.metadata) == null ? void 0 : _a.source_table;
453
479
  if (!resultsByTable[table]) resultsByTable[table] = [];
454
480
  resultsByTable[table].push(res);
455
481
  }
@@ -461,7 +487,7 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
461
487
  const finalSorted = balancedResults.sort((a, b) => b.score - a.score);
462
488
  if (finalSorted.length > 0) {
463
489
  console.log(`[MultiTablePostgresProvider] --- Search Complete ---`);
464
- console.log(`[MultiTablePostgresProvider] Final top match from "${(_d = (_c = finalSorted[0].metadata) == null ? void 0 : _c.source_table) != null ? _d : "unknown"}" with score ${finalSorted[0].score.toFixed(4)}`);
490
+ console.log(`[MultiTablePostgresProvider] Final top match from "${(_c = (_b = finalSorted[0].metadata) == null ? void 0 : _b.source_table) != null ? _c : "unknown"}" with score ${finalSorted[0].score.toFixed(4)}`);
465
491
  }
466
492
  return finalSorted.slice(0, Math.max(topK, 15));
467
493
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retrivora-ai/rag-engine",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
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",
@@ -135,7 +135,8 @@ export class Pipeline {
135
135
 
136
136
  try {
137
137
  const queryVector = await this.embeddingProvider.embed(question, { taskType: 'query' });
138
- const rawMatches = await this.vectorDB.query(queryVector, topK, ns);
138
+ // Pass the original text to the vector DB so it can perform hybrid (keyword) search if supported
139
+ const rawMatches = await this.vectorDB.query(queryVector, topK, ns, { __queryText: question });
139
140
 
140
141
  const sources = rawMatches.filter((m) => m.score >= scoreThreshold);
141
142
  const context = sources.length
@@ -1,3 +1,6 @@
1
+
2
+
3
+
1
4
  import { Pool, PoolClient } from 'pg';
2
5
  import { BaseVectorProvider } from './BaseVectorProvider';
3
6
  import { VectorMatch, UpsertDocument } from '../../types';
@@ -46,7 +49,7 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
46
49
 
47
50
  async initialize(): Promise<void> {
48
51
  this.pool = new Pool({ connectionString: this.connectionString });
49
-
52
+
50
53
  // Dynamically discover all tables that have an 'embedding' column
51
54
  const client: PoolClient = await this.pool.connect();
52
55
  try {
@@ -56,9 +59,9 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
56
59
  WHERE column_name = 'embedding'
57
60
  AND table_schema = 'public'
58
61
  `);
59
-
62
+
60
63
  const discoveredTables = res.rows.map(r => r.table_name);
61
-
64
+
62
65
  if (this.tables.length === 0) {
63
66
  // No static tables configured, use everything discovered
64
67
  this.tables = discoveredTables;
@@ -66,7 +69,7 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
66
69
  // Filter configured tables to ensure they actually exist with embeddings
67
70
  const staticTables = [...this.tables];
68
71
  this.tables = staticTables.filter(t => discoveredTables.includes(t));
69
-
72
+
70
73
  if (this.tables.length < staticTables.length) {
71
74
  const missing = staticTables.filter(t => !discoveredTables.includes(t));
72
75
  console.warn(`[MultiTablePostgresProvider] Some configured tables were skipped (missing 'embedding' column): ${missing.join(', ')}`);
@@ -111,8 +114,8 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
111
114
  async query(
112
115
  vector: number[],
113
116
  topK: number,
114
- _namespace?: string, // eslint-disable-line @typescript-eslint/no-unused-vars
115
- _filter?: Record<string, unknown> // eslint-disable-line @typescript-eslint/no-unused-vars
117
+ _namespace?: string,
118
+ _filter?: Record<string, unknown>
116
119
  ): Promise<VectorMatch[]> {
117
120
  if (!this.pool) {
118
121
  throw new Error('[MultiTablePostgresProvider] Provider not initialized. Call initialize() first.');
@@ -123,49 +126,78 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
123
126
 
124
127
  console.log(`[MultiTablePostgresProvider] --- Starting Multi-Table Search ---`);
125
128
 
126
- for (const table of this.tables) {
129
+ const queryText = _filter?.__queryText as string | undefined;
130
+
131
+ const queryPromises = this.tables.map(async (table) => {
127
132
  try {
128
- // We use a hybrid approach:
129
- // 1. Vector similarity (Semantic)
130
- // 2. Simple keyword matching (Exact) to boost relevance for specific names
131
- const result = await this.pool.query(
132
- `SELECT *,
133
- (1 - (embedding <=> $1::vector)) AS vector_score
134
- FROM "${table}"
135
- ORDER BY vector_score DESC
136
- LIMIT 50`,
137
- [vectorLiteral]
138
- );
133
+ let sqlQuery = '';
134
+ let params: unknown[] = [];
135
+
136
+ if (queryText) {
137
+ // Actual Hybrid Search: Semantic Vector Score + Full-Text Keyword Rank
138
+ sqlQuery = `
139
+ SELECT *,
140
+ (1 - (embedding <=> $1::vector)) AS vector_score,
141
+ ts_rank(to_tsvector('english', t.*::text), plainto_tsquery('english', $2)) AS keyword_score,
142
+ ((1 - (embedding <=> $1::vector)) + (ts_rank(to_tsvector('english', t.*::text), plainto_tsquery('english', $2)) * 2.0)) AS hybrid_score
143
+ FROM "${table}" t
144
+ ORDER BY hybrid_score DESC
145
+ LIMIT 50
146
+ `;
147
+ params = [vectorLiteral, queryText];
148
+ } else {
149
+ // Fallback to Vector-only Search
150
+ sqlQuery = `
151
+ SELECT *,
152
+ (1 - (embedding <=> $1::vector)) AS hybrid_score
153
+ FROM "${table}" t
154
+ ORDER BY hybrid_score DESC
155
+ LIMIT 50
156
+ `;
157
+ params = [vectorLiteral];
158
+ }
159
+
160
+ const result = await this.pool.query(sqlQuery, params);
139
161
 
140
162
  if (result.rowCount && result.rowCount > 0) {
141
- console.log(` ✅ Table "${table}": Found ${result.rowCount} potential matches. Top score: ${result.rows[0].vector_score.toFixed(4)}`);
163
+ console.log(` ✅ Table "${table}": Found ${result.rowCount} potential matches. Top score: ${result.rows[0].hybrid_score.toFixed(4)}`);
142
164
  } else {
143
165
  console.log(` ⚪ Table "${table}": No relevant matches found.`);
144
166
  }
145
167
 
168
+ const tableResults: VectorMatch[] = [];
146
169
  for (const row of result.rows) {
147
- const { vector_score, id, ...rest } = row as Record<string, unknown>;
170
+ const { hybrid_score, id, ...rest } = row as Record<string, unknown>;
148
171
  delete rest.embedding;
172
+ delete rest.vector_score;
173
+ delete rest.keyword_score;
149
174
 
150
- const content = `[TYPE: ${table.replace(/s$/, '').toUpperCase()}]\n` +
175
+ const content = `[TYPE: ${table.replace(/s$/, '').toUpperCase()}]\n` +
151
176
  Object.entries(rest)
152
177
  .filter(([k, v]) => v !== null && typeof v !== 'object' && k !== 'id')
153
178
  .map(([k, v]) => `${k}: ${v}`)
154
179
  .join('\n');
155
180
 
156
- allResults.push({
181
+ tableResults.push({
157
182
  id: `${table}-${id}`,
158
- score: parseFloat(String(vector_score)),
183
+ score: parseFloat(String(hybrid_score)),
159
184
  content,
160
185
  metadata: { ...rest, source_table: table },
161
186
  });
162
187
  }
188
+ return tableResults;
163
189
  } catch (err) {
164
190
  console.error(
165
191
  `[MultiTablePostgresProvider] Error querying table "${table}":`,
166
192
  (err as Error).message
167
193
  );
194
+ return [];
168
195
  }
196
+ });
197
+
198
+ const resultsArray = await Promise.all(queryPromises);
199
+ for (const tableResults of resultsArray) {
200
+ allResults.push(...tableResults);
169
201
  }
170
202
 
171
203
  // 1. Group results by table to ensure we take the top ones from each
@@ -179,7 +211,7 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
179
211
  // 2. Take top 3 from EACH table guaranteed, then fill the rest with overall best
180
212
  const balancedResults: VectorMatch[] = [];
181
213
  const tables = Object.keys(resultsByTable);
182
-
214
+
183
215
  // First, ensure every table's best match is included
184
216
  for (const table of tables) {
185
217
  balancedResults.push(...resultsByTable[table].slice(0, 3));