@retrivora-ai/rag-engine 0.2.3 → 0.2.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.
@@ -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.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.";
@@ -3770,29 +3770,46 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
3770
3770
  const vectorLiteral = `[${vector.join(",")}]`;
3771
3771
  const allResults = [];
3772
3772
  console.log(`[MultiTablePostgresProvider] --- Starting Multi-Table Search ---`);
3773
+ const queryText = _filter == null ? void 0 : _filter.__queryText;
3773
3774
  for (const table of this.tables) {
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
  }
3788
3805
  for (const row of result.rows) {
3789
- const _a = row, { vector_score, id } = _a, rest = __objRest(_a, ["vector_score", "id"]);
3806
+ const _a = row, { hybrid_score, vector_score, keyword_score, id } = _a, rest = __objRest(_a, ["hybrid_score", "vector_score", "keyword_score", "id"]);
3790
3807
  delete rest.embedding;
3791
3808
  const content = `[TYPE: ${table.replace(/s$/, "").toUpperCase()}]
3792
3809
  ` + Object.entries(rest).filter(([k, v]) => v !== null && typeof v !== "object" && k !== "id").map(([k, v]) => `${k}: ${v}`).join("\n");
3793
3810
  allResults.push({
3794
3811
  id: `${table}-${id}`,
3795
- score: parseFloat(String(vector_score)),
3812
+ score: parseFloat(String(hybrid_score)),
3796
3813
  content,
3797
3814
  metadata: __spreadProps(__spreadValues({}, rest), { source_table: table })
3798
3815
  });
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
@@ -413,29 +413,46 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
413
413
  const vectorLiteral = `[${vector.join(",")}]`;
414
414
  const allResults = [];
415
415
  console.log(`[MultiTablePostgresProvider] --- Starting Multi-Table Search ---`);
416
+ const queryText = _filter == null ? void 0 : _filter.__queryText;
416
417
  for (const table of this.tables) {
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
  }
431
448
  for (const row of result.rows) {
432
- const _a = row, { vector_score, id } = _a, rest = __objRest(_a, ["vector_score", "id"]);
449
+ const _a = row, { hybrid_score, vector_score, keyword_score, id } = _a, rest = __objRest(_a, ["hybrid_score", "vector_score", "keyword_score", "id"]);
433
450
  delete rest.embedding;
434
451
  const content = `[TYPE: ${table.replace(/s$/, "").toUpperCase()}]
435
452
  ` + Object.entries(rest).filter(([k, v]) => v !== null && typeof v !== "object" && k !== "id").map(([k, v]) => `${k}: ${v}`).join("\n");
436
453
  allResults.push({
437
454
  id: `${table}-${id}`,
438
- score: parseFloat(String(vector_score)),
455
+ score: parseFloat(String(hybrid_score)),
439
456
  content,
440
457
  metadata: __spreadProps(__spreadValues({}, rest), { source_table: table })
441
458
  });
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.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",
@@ -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
@@ -46,7 +46,7 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
46
46
 
47
47
  async initialize(): Promise<void> {
48
48
  this.pool = new Pool({ connectionString: this.connectionString });
49
-
49
+
50
50
  // Dynamically discover all tables that have an 'embedding' column
51
51
  const client: PoolClient = await this.pool.connect();
52
52
  try {
@@ -56,9 +56,9 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
56
56
  WHERE column_name = 'embedding'
57
57
  AND table_schema = 'public'
58
58
  `);
59
-
59
+
60
60
  const discoveredTables = res.rows.map(r => r.table_name);
61
-
61
+
62
62
  if (this.tables.length === 0) {
63
63
  // No static tables configured, use everything discovered
64
64
  this.tables = discoveredTables;
@@ -66,7 +66,7 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
66
66
  // Filter configured tables to ensure they actually exist with embeddings
67
67
  const staticTables = [...this.tables];
68
68
  this.tables = staticTables.filter(t => discoveredTables.includes(t));
69
-
69
+
70
70
  if (this.tables.length < staticTables.length) {
71
71
  const missing = staticTables.filter(t => !discoveredTables.includes(t));
72
72
  console.warn(`[MultiTablePostgresProvider] Some configured tables were skipped (missing 'embedding' column): ${missing.join(', ')}`);
@@ -123,31 +123,50 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
123
123
 
124
124
  console.log(`[MultiTablePostgresProvider] --- Starting Multi-Table Search ---`);
125
125
 
126
+ const queryText = _filter?.__queryText as string | undefined;
127
+
126
128
  for (const table of this.tables) {
127
129
  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
- );
130
+ let sqlQuery = '';
131
+ let params: any[] = [];
132
+
133
+ if (queryText) {
134
+ // Actual Hybrid Search: Semantic Vector Score + Full-Text Keyword Rank
135
+ sqlQuery = `
136
+ SELECT *,
137
+ (1 - (embedding <=> $1::vector)) AS vector_score,
138
+ ts_rank(to_tsvector('english', t.*::text), plainto_tsquery('english', $2)) AS keyword_score,
139
+ ((1 - (embedding <=> $1::vector)) + (ts_rank(to_tsvector('english', t.*::text), plainto_tsquery('english', $2)) * 2.0)) AS hybrid_score
140
+ FROM "${table}" t
141
+ ORDER BY hybrid_score DESC
142
+ LIMIT 50
143
+ `;
144
+ params = [vectorLiteral, queryText];
145
+ } else {
146
+ // Fallback to Vector-only Search
147
+ sqlQuery = `
148
+ SELECT *,
149
+ (1 - (embedding <=> $1::vector)) AS hybrid_score
150
+ FROM "${table}" t
151
+ ORDER BY hybrid_score DESC
152
+ LIMIT 50
153
+ `;
154
+ params = [vectorLiteral];
155
+ }
156
+
157
+ const result = await this.pool.query(sqlQuery, params);
139
158
 
140
159
  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)}`);
160
+ console.log(` ✅ Table "${table}": Found ${result.rowCount} potential matches. Top score: ${result.rows[0].hybrid_score.toFixed(4)}`);
142
161
  } else {
143
162
  console.log(` ⚪ Table "${table}": No relevant matches found.`);
144
163
  }
145
164
 
146
165
  for (const row of result.rows) {
147
- const { vector_score, id, ...rest } = row as Record<string, unknown>;
166
+ const { hybrid_score, vector_score, keyword_score, id, ...rest } = row as Record<string, unknown>;
148
167
  delete rest.embedding;
149
168
 
150
- const content = `[TYPE: ${table.replace(/s$/, '').toUpperCase()}]\n` +
169
+ const content = `[TYPE: ${table.replace(/s$/, '').toUpperCase()}]\n` +
151
170
  Object.entries(rest)
152
171
  .filter(([k, v]) => v !== null && typeof v !== 'object' && k !== 'id')
153
172
  .map(([k, v]) => `${k}: ${v}`)
@@ -155,7 +174,7 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
155
174
 
156
175
  allResults.push({
157
176
  id: `${table}-${id}`,
158
- score: parseFloat(String(vector_score)),
177
+ score: parseFloat(String(hybrid_score)),
159
178
  content,
160
179
  metadata: { ...rest, source_table: table },
161
180
  });
@@ -179,7 +198,7 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
179
198
  // 2. Take top 3 from EACH table guaranteed, then fill the rest with overall best
180
199
  const balancedResults: VectorMatch[] = [];
181
200
  const tables = Object.keys(resultsByTable);
182
-
201
+
183
202
  // First, ensure every table's best match is included
184
203
  for (const table of tables) {
185
204
  balancedResults.push(...resultsByTable[table].slice(0, 3));