@retrivora-ai/rag-engine 1.7.4 → 1.7.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.
@@ -829,7 +829,8 @@ ${context}`;
829
829
  stopSequences: options == null ? void 0 : options.stop
830
830
  }
831
831
  });
832
- return (_f = response.text) != null ? _f : "";
832
+ const text = typeof response.text === "function" ? response.text() : (_f = response.text) != null ? _f : "";
833
+ return text;
833
834
  }
834
835
  chatStream(messages, context, options) {
835
836
  return __asyncGenerator(this, null, function* () {
@@ -863,7 +864,7 @@ ${context}`;
863
864
  try {
864
865
  for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
865
866
  const chunk = temp.value;
866
- const text = chunk.text;
867
+ const text = typeof chunk.text === "function" ? chunk.text() : chunk.text;
867
868
  if (text) yield text;
868
869
  }
869
870
  } catch (temp) {
@@ -2445,7 +2446,10 @@ User: "distribution of products across categories"
2445
2446
  \`\`\`
2446
2447
  `;
2447
2448
  if (!((_a = this.config.llm.systemPrompt) == null ? void 0 : _a.includes(CHART_MARKER))) {
2448
- this.config.llm.systemPrompt = (this.config.llm.systemPrompt || "") + chartInstruction;
2449
+ let cleanPrompt = this.config.llm.systemPrompt || "";
2450
+ cleanPrompt = cleanPrompt.replace(/\n\n### UNIVERSAL UI PROTOCOL[\s\S]*?(?=\n\n|$)/g, "");
2451
+ cleanPrompt = cleanPrompt.replace(/<!-- UI_PROTOCOL_V\d+ -->[\s\S]*?(?=\n\n|$)/g, "");
2452
+ this.config.llm.systemPrompt = cleanPrompt.trim() + chartInstruction;
2449
2453
  }
2450
2454
  console.log(`[Pipeline] Initializing with provider: ${this.config.vectorDb.provider}...`);
2451
2455
  this.vectorDB = await ProviderRegistry.createVectorProvider(this.config.vectorDb);
@@ -2437,7 +2437,8 @@ ${context}`;
2437
2437
  stopSequences: options == null ? void 0 : options.stop
2438
2438
  }
2439
2439
  });
2440
- return (_f = response.text) != null ? _f : "";
2440
+ const text = typeof response.text === "function" ? response.text() : (_f = response.text) != null ? _f : "";
2441
+ return text;
2441
2442
  }
2442
2443
  chatStream(messages, context, options) {
2443
2444
  return __asyncGenerator(this, null, function* () {
@@ -2471,7 +2472,7 @@ ${context}`;
2471
2472
  try {
2472
2473
  for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
2473
2474
  const chunk = temp.value;
2474
- const text = chunk.text;
2475
+ const text = typeof chunk.text === "function" ? chunk.text() : chunk.text;
2475
2476
  if (text) yield text;
2476
2477
  }
2477
2478
  } catch (temp) {
@@ -4009,7 +4010,10 @@ User: "distribution of products across categories"
4009
4010
  \`\`\`
4010
4011
  `;
4011
4012
  if (!((_a = this.config.llm.systemPrompt) == null ? void 0 : _a.includes(CHART_MARKER))) {
4012
- this.config.llm.systemPrompt = (this.config.llm.systemPrompt || "") + chartInstruction;
4013
+ let cleanPrompt = this.config.llm.systemPrompt || "";
4014
+ cleanPrompt = cleanPrompt.replace(/\n\n### UNIVERSAL UI PROTOCOL[\s\S]*?(?=\n\n|$)/g, "");
4015
+ cleanPrompt = cleanPrompt.replace(/<!-- UI_PROTOCOL_V\d+ -->[\s\S]*?(?=\n\n|$)/g, "");
4016
+ this.config.llm.systemPrompt = cleanPrompt.trim() + chartInstruction;
4013
4017
  }
4014
4018
  console.log(`[Pipeline] Initializing with provider: ${this.config.vectorDb.provider}...`);
4015
4019
  this.vectorDB = await ProviderRegistry.createVectorProvider(this.config.vectorDb);
@@ -10,7 +10,7 @@ import {
10
10
  sseMetaFrame,
11
11
  sseTextFrame,
12
12
  sseUIFrame
13
- } from "../chunk-PKK7EEVP.mjs";
13
+ } from "../chunk-QOO37S2Z.mjs";
14
14
  import "../chunk-YLTMFW4M.mjs";
15
15
  import "../chunk-X4TOT24V.mjs";
16
16
  export {
package/dist/index.js CHANGED
@@ -637,6 +637,11 @@ function normalizeTabularRows(rows, columns) {
637
637
  }).filter((row) => Object.keys(row).length > 0);
638
638
  }
639
639
  function resolveStructuredRows(config) {
640
+ var _a, _b, _c, _d;
641
+ if (((_a = config.carousel) == null ? void 0 : _a.items) && Array.isArray(config.carousel.items)) return config.carousel.items;
642
+ if (((_b = config.chart) == null ? void 0 : _b.data) && Array.isArray(config.chart.data)) return config.chart.data;
643
+ if (((_c = config.table) == null ? void 0 : _c.rows) && Array.isArray(config.table.rows)) return config.table.rows;
644
+ if (((_d = config.table) == null ? void 0 : _d.data) && Array.isArray(config.table.data)) return config.table.data;
640
645
  if (Array.isArray(config.data) && config.data.length > 0) return config.data;
641
646
  if (Array.isArray(config.items) && config.items.length > 0) return config.items;
642
647
  if (Array.isArray(config.products) && config.products.length > 0) return config.products;
@@ -652,6 +657,14 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
652
657
  const clean = rawContent.replace(/^```[a-z]*\s*/i, "").replace(/```\s*$/, "").trim();
653
658
  const parsed = JSON.parse(sanitizeJson(extractLikelyJsonBlock(clean)));
654
659
  const config2 = __spreadValues({}, parsed);
660
+ if (config2.chart) {
661
+ if (!config2.chartType) config2.chartType = config2.chart.type;
662
+ if (!config2.xAxisKey) config2.xAxisKey = config2.chart.xKey;
663
+ if (!config2.dataKeys) config2.dataKeys = config2.chart.yKeys;
664
+ }
665
+ if (config2.table) {
666
+ if (!config2.columns) config2.columns = config2.table.columns;
667
+ }
655
668
  const resolvedRows = resolveStructuredRows(config2);
656
669
  const hasProductLikeData = resolvedRows.length > 0 && typeof resolvedRows[0] === "object" && resolvedRows[0] !== null && !Array.isArray(resolvedRows[0]) && (["price", "brand", "image", "link", "thumbnail"].some((key) => key in resolvedRows[0]) || Object.keys(resolvedRows[0]).length >= 4);
657
670
  const hasAggregationLikeData = resolvedRows.length > 0 && typeof resolvedRows[0] === "object" && resolvedRows[0] !== null && !Array.isArray(resolvedRows[0]) && (["value", "count", "total", "percentage"].some((key) => key in resolvedRows[0]) || Object.keys(resolvedRows[0]).length <= 3 && Object.values(resolvedRows[0]).some((v) => typeof v === "number"));
package/dist/index.mjs CHANGED
@@ -600,6 +600,11 @@ function normalizeTabularRows(rows, columns) {
600
600
  }).filter((row) => Object.keys(row).length > 0);
601
601
  }
602
602
  function resolveStructuredRows(config) {
603
+ var _a, _b, _c, _d;
604
+ if (((_a = config.carousel) == null ? void 0 : _a.items) && Array.isArray(config.carousel.items)) return config.carousel.items;
605
+ if (((_b = config.chart) == null ? void 0 : _b.data) && Array.isArray(config.chart.data)) return config.chart.data;
606
+ if (((_c = config.table) == null ? void 0 : _c.rows) && Array.isArray(config.table.rows)) return config.table.rows;
607
+ if (((_d = config.table) == null ? void 0 : _d.data) && Array.isArray(config.table.data)) return config.table.data;
603
608
  if (Array.isArray(config.data) && config.data.length > 0) return config.data;
604
609
  if (Array.isArray(config.items) && config.items.length > 0) return config.items;
605
610
  if (Array.isArray(config.products) && config.products.length > 0) return config.products;
@@ -615,6 +620,14 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
615
620
  const clean = rawContent.replace(/^```[a-z]*\s*/i, "").replace(/```\s*$/, "").trim();
616
621
  const parsed = JSON.parse(sanitizeJson(extractLikelyJsonBlock(clean)));
617
622
  const config2 = __spreadValues({}, parsed);
623
+ if (config2.chart) {
624
+ if (!config2.chartType) config2.chartType = config2.chart.type;
625
+ if (!config2.xAxisKey) config2.xAxisKey = config2.chart.xKey;
626
+ if (!config2.dataKeys) config2.dataKeys = config2.chart.yKeys;
627
+ }
628
+ if (config2.table) {
629
+ if (!config2.columns) config2.columns = config2.table.columns;
630
+ }
618
631
  const resolvedRows = resolveStructuredRows(config2);
619
632
  const hasProductLikeData = resolvedRows.length > 0 && typeof resolvedRows[0] === "object" && resolvedRows[0] !== null && !Array.isArray(resolvedRows[0]) && (["price", "brand", "image", "link", "thumbnail"].some((key) => key in resolvedRows[0]) || Object.keys(resolvedRows[0]).length >= 4);
620
633
  const hasAggregationLikeData = resolvedRows.length > 0 && typeof resolvedRows[0] === "object" && resolvedRows[0] !== null && !Array.isArray(resolvedRows[0]) && (["value", "count", "total", "percentage"].some((key) => key in resolvedRows[0]) || Object.keys(resolvedRows[0]).length <= 3 && Object.values(resolvedRows[0]).some((v) => typeof v === "number"));
package/dist/server.js CHANGED
@@ -2482,7 +2482,8 @@ ${context}`;
2482
2482
  stopSequences: options == null ? void 0 : options.stop
2483
2483
  }
2484
2484
  });
2485
- return (_f = response.text) != null ? _f : "";
2485
+ const text = typeof response.text === "function" ? response.text() : (_f = response.text) != null ? _f : "";
2486
+ return text;
2486
2487
  }
2487
2488
  chatStream(messages, context, options) {
2488
2489
  return __asyncGenerator(this, null, function* () {
@@ -2516,7 +2517,7 @@ ${context}`;
2516
2517
  try {
2517
2518
  for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
2518
2519
  const chunk = temp.value;
2519
- const text = chunk.text;
2520
+ const text = typeof chunk.text === "function" ? chunk.text() : chunk.text;
2520
2521
  if (text) yield text;
2521
2522
  }
2522
2523
  } catch (temp) {
@@ -4099,7 +4100,10 @@ User: "distribution of products across categories"
4099
4100
  \`\`\`
4100
4101
  `;
4101
4102
  if (!((_a = this.config.llm.systemPrompt) == null ? void 0 : _a.includes(CHART_MARKER))) {
4102
- this.config.llm.systemPrompt = (this.config.llm.systemPrompt || "") + chartInstruction;
4103
+ let cleanPrompt = this.config.llm.systemPrompt || "";
4104
+ cleanPrompt = cleanPrompt.replace(/\n\n### UNIVERSAL UI PROTOCOL[\s\S]*?(?=\n\n|$)/g, "");
4105
+ cleanPrompt = cleanPrompt.replace(/<!-- UI_PROTOCOL_V\d+ -->[\s\S]*?(?=\n\n|$)/g, "");
4106
+ this.config.llm.systemPrompt = cleanPrompt.trim() + chartInstruction;
4103
4107
  }
4104
4108
  console.log(`[Pipeline] Initializing with provider: ${this.config.vectorDb.provider}...`);
4105
4109
  this.vectorDB = await ProviderRegistry.createVectorProvider(this.config.vectorDb);
@@ -4923,11 +4927,15 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
4923
4927
  ).map((hint) => hint.value.trim().toLowerCase()).filter(Boolean) : [];
4924
4928
  console.log(`[MultiTablePostgresProvider] queryText: "${queryText}"`);
4925
4929
  console.log(`[MultiTablePostgresProvider] entityHints: [${entityHints.join(", ")}]`);
4930
+ const cleanKeywordQuery = (text) => {
4931
+ return text.toLowerCase().replace(/\b(show|me|the|product|cards|of|category|find|list|browse|what|are|display)\b/g, "").trim().replace(/\s+/g, " & ");
4932
+ };
4926
4933
  const queryPromises = this.tables.map(async (table) => {
4927
4934
  try {
4928
4935
  let sqlQuery = "";
4929
4936
  let params = [];
4930
4937
  if (queryText) {
4938
+ const cleanedText = cleanKeywordQuery(queryText) || queryText;
4931
4939
  const hasEntityHints = entityHints.length > 0;
4932
4940
  const exactNameScoreExpr = hasEntityHints ? `+ (
4933
4941
  SELECT COALESCE(MAX(
@@ -4940,13 +4948,13 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
4940
4948
  sqlQuery = `
4941
4949
  SELECT *,
4942
4950
  (1 - (embedding <=> $1::vector)) AS vector_score,
4943
- COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), NULLIF(REPLACE(plainto_tsquery('english', $2)::text, '&', '|'), '')::tsquery), 0) AS keyword_score,
4944
- ((1 - (embedding <=> $1::vector)) + (COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), NULLIF(REPLACE(plainto_tsquery('english', $2)::text, '&', '|'), '')::tsquery), 0) * 2.0) ${exactNameScoreExpr}) AS hybrid_score
4951
+ COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), to_tsquery('english', $2)), 0) AS keyword_score,
4952
+ ((1 - (embedding <=> $1::vector)) + (COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), to_tsquery('english', $2)), 0) * 2.0) ${exactNameScoreExpr}) AS hybrid_score
4945
4953
  FROM "${table}" t
4946
4954
  ORDER BY hybrid_score DESC
4947
4955
  LIMIT 50
4948
4956
  `;
4949
- params = [vectorLiteral, queryText];
4957
+ params = [vectorLiteral, cleanedText];
4950
4958
  } else {
4951
4959
  sqlQuery = `
4952
4960
  SELECT *,
package/dist/server.mjs CHANGED
@@ -39,7 +39,7 @@ import {
39
39
  sseFrame,
40
40
  sseMetaFrame,
41
41
  sseTextFrame
42
- } from "./chunk-PKK7EEVP.mjs";
42
+ } from "./chunk-QOO37S2Z.mjs";
43
43
  import "./chunk-YLTMFW4M.mjs";
44
44
  import {
45
45
  PineconeProvider
@@ -325,11 +325,15 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
325
325
  ).map((hint) => hint.value.trim().toLowerCase()).filter(Boolean) : [];
326
326
  console.log(`[MultiTablePostgresProvider] queryText: "${queryText}"`);
327
327
  console.log(`[MultiTablePostgresProvider] entityHints: [${entityHints.join(", ")}]`);
328
+ const cleanKeywordQuery = (text) => {
329
+ return text.toLowerCase().replace(/\b(show|me|the|product|cards|of|category|find|list|browse|what|are|display)\b/g, "").trim().replace(/\s+/g, " & ");
330
+ };
328
331
  const queryPromises = this.tables.map(async (table) => {
329
332
  try {
330
333
  let sqlQuery = "";
331
334
  let params = [];
332
335
  if (queryText) {
336
+ const cleanedText = cleanKeywordQuery(queryText) || queryText;
333
337
  const hasEntityHints = entityHints.length > 0;
334
338
  const exactNameScoreExpr = hasEntityHints ? `+ (
335
339
  SELECT COALESCE(MAX(
@@ -342,13 +346,13 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
342
346
  sqlQuery = `
343
347
  SELECT *,
344
348
  (1 - (embedding <=> $1::vector)) AS vector_score,
345
- COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), NULLIF(REPLACE(plainto_tsquery('english', $2)::text, '&', '|'), '')::tsquery), 0) AS keyword_score,
346
- ((1 - (embedding <=> $1::vector)) + (COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), NULLIF(REPLACE(plainto_tsquery('english', $2)::text, '&', '|'), '')::tsquery), 0) * 2.0) ${exactNameScoreExpr}) AS hybrid_score
349
+ COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), to_tsquery('english', $2)), 0) AS keyword_score,
350
+ ((1 - (embedding <=> $1::vector)) + (COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), to_tsquery('english', $2)), 0) * 2.0) ${exactNameScoreExpr}) AS hybrid_score
347
351
  FROM "${table}" t
348
352
  ORDER BY hybrid_score DESC
349
353
  LIMIT 50
350
354
  `;
351
- params = [vectorLiteral, queryText];
355
+ params = [vectorLiteral, cleanedText];
352
356
  } else {
353
357
  sqlQuery = `
354
358
  SELECT *,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retrivora-ai/rag-engine",
3
- "version": "1.7.4",
3
+ "version": "1.7.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",
@@ -381,14 +381,46 @@ interface UIConfig {
381
381
  rows?: Record<string, unknown>[];
382
382
  products?: Record<string, unknown>[];
383
383
  results?: Record<string, unknown>[];
384
+
385
+ // V7 Protocol Fields
386
+ carousel?: {
387
+ items: Record<string, unknown>[];
388
+ };
389
+ chart?: {
390
+ type: 'pie' | 'bar' | 'line';
391
+ xKey: string;
392
+ yKeys: string[];
393
+ data: Record<string, unknown>[];
394
+ };
395
+ table?: {
396
+ columns: string[];
397
+ rows?: Record<string, unknown>[];
398
+ data?: Record<string, unknown>[];
399
+ };
384
400
  }
385
401
 
386
- interface RawUIConfig extends Omit<UIConfig, 'data' | 'items' | 'rows' | 'products' | 'results'> {
402
+ interface RawUIConfig extends Omit<UIConfig, 'data' | 'items' | 'rows' | 'products' | 'results' | 'carousel' | 'chart' | 'table'> {
387
403
  data: Array<Record<string, unknown> | unknown[]>;
388
404
  items?: Array<Record<string, unknown> | unknown[]>;
389
405
  rows?: Array<Record<string, unknown> | unknown[]>;
390
406
  products?: Array<Record<string, unknown> | unknown[]>;
391
407
  results?: Array<Record<string, unknown> | unknown[]>;
408
+
409
+ // V7 Protocol Fields (Raw)
410
+ carousel?: {
411
+ items: Array<Record<string, unknown> | unknown[]>;
412
+ };
413
+ chart?: {
414
+ type: 'pie' | 'bar' | 'line';
415
+ xKey: string;
416
+ yKeys: string[];
417
+ data: Array<Record<string, unknown> | unknown[]>;
418
+ };
419
+ table?: {
420
+ columns: string[];
421
+ rows?: Array<Record<string, unknown> | unknown[]>;
422
+ data?: Array<Record<string, unknown> | unknown[]>;
423
+ };
392
424
  }
393
425
 
394
426
  function normalizeTabularRows(
@@ -420,6 +452,13 @@ function normalizeTabularRows(
420
452
  }
421
453
 
422
454
  function resolveStructuredRows(config: Partial<RawUIConfig> & Record<string, unknown>) {
455
+ // V7 Nested Structures
456
+ if (config.carousel?.items && Array.isArray(config.carousel.items)) return config.carousel.items;
457
+ if (config.chart?.data && Array.isArray(config.chart.data)) return config.chart.data;
458
+ if (config.table?.rows && Array.isArray(config.table.rows)) return config.table.rows;
459
+ if (config.table?.data && Array.isArray(config.table.data)) return config.table.data;
460
+
461
+ // V6 Flat Structures
423
462
  if (Array.isArray(config.data) && config.data.length > 0) return config.data;
424
463
  if (Array.isArray(config.items) && config.items.length > 0) return config.items;
425
464
  if (Array.isArray(config.products) && config.products.length > 0) return config.products;
@@ -445,6 +484,17 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
445
484
  .trim();
446
485
  const parsed = JSON.parse(sanitizeJson(extractLikelyJsonBlock(clean)));
447
486
  const config = { ...parsed } as Partial<RawUIConfig> & Record<string, unknown>;
487
+
488
+ // V7 Field Mapping
489
+ if (config.chart) {
490
+ if (!config.chartType) config.chartType = config.chart.type;
491
+ if (!config.xAxisKey) config.xAxisKey = config.chart.xKey;
492
+ if (!config.dataKeys) config.dataKeys = config.chart.yKeys;
493
+ }
494
+ if (config.table) {
495
+ if (!config.columns) config.columns = config.table.columns;
496
+ }
497
+
448
498
  const resolvedRows = resolveStructuredRows(config);
449
499
 
450
500
  // ─── Intent Healing & Auto-Detection ───────────────────────────────────
@@ -287,7 +287,12 @@ User: "distribution of products across categories"
287
287
  \`\`\`
288
288
  `;
289
289
  if (!this.config.llm.systemPrompt?.includes(CHART_MARKER)) {
290
- this.config.llm.systemPrompt = (this.config.llm.systemPrompt || '') + chartInstruction;
290
+ // Clean up ANY existing protocol markers (V1-V7) to avoid prompt bloat
291
+ let cleanPrompt = this.config.llm.systemPrompt || '';
292
+ cleanPrompt = cleanPrompt.replace(/\n\n### UNIVERSAL UI PROTOCOL[\s\S]*?(?=\n\n|$)/g, '');
293
+ cleanPrompt = cleanPrompt.replace(/<!-- UI_PROTOCOL_V\d+ -->[\s\S]*?(?=\n\n|$)/g, '');
294
+
295
+ this.config.llm.systemPrompt = cleanPrompt.trim() + chartInstruction;
291
296
  }
292
297
 
293
298
  console.log(`[Pipeline] Initializing with provider: ${this.config.vectorDb.provider}...`);
@@ -128,7 +128,10 @@ export class GeminiProvider implements ILLMProvider {
128
128
  },
129
129
  });
130
130
 
131
- return response.text ?? '';
131
+ const text = typeof (response as { text: unknown }).text === 'function'
132
+ ? (response as { text: () => string }).text()
133
+ : (response.text ?? '');
134
+ return text;
132
135
  }
133
136
 
134
137
  async *chatStream(messages: ChatMessage[], context: string, options?: ChatOptions): AsyncIterable<string> {
@@ -162,7 +165,9 @@ export class GeminiProvider implements ILLMProvider {
162
165
  }
163
166
 
164
167
  for await (const chunk of stream) {
165
- const text = chunk.text;
168
+ const text = typeof (chunk as { text: unknown }).text === 'function'
169
+ ? (chunk as { text: () => string }).text()
170
+ : (chunk as { text?: string }).text;
166
171
  if (text) yield text;
167
172
  }
168
173
  }
@@ -151,12 +151,22 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
151
151
  console.log(`[MultiTablePostgresProvider] queryText: "${queryText}"`);
152
152
  console.log(`[MultiTablePostgresProvider] entityHints: [${entityHints.join(', ')}]`);
153
153
 
154
+ // Helper to clean conversational filler for better keyword matching
155
+ const cleanKeywordQuery = (text: string) => {
156
+ return text
157
+ .toLowerCase()
158
+ .replace(/\b(show|me|the|product|cards|of|category|find|list|browse|what|are|display)\b/g, '')
159
+ .trim()
160
+ .replace(/\s+/g, ' & '); // Join remaining words with AND for tsquery
161
+ };
162
+
154
163
  const queryPromises = this.tables.map(async (table) => {
155
164
  try {
156
165
  let sqlQuery = '';
157
166
  let params: unknown[] = [];
158
167
 
159
168
  if (queryText) {
169
+ const cleanedText = cleanKeywordQuery(queryText) || queryText;
160
170
  const hasEntityHints = entityHints.length > 0;
161
171
  const exactNameScoreExpr = hasEntityHints
162
172
  ? `+ (
@@ -173,13 +183,13 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
173
183
  sqlQuery = `
174
184
  SELECT *,
175
185
  (1 - (embedding <=> $1::vector)) AS vector_score,
176
- COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), NULLIF(REPLACE(plainto_tsquery('english', $2)::text, '&', '|'), '')::tsquery), 0) AS keyword_score,
177
- ((1 - (embedding <=> $1::vector)) + (COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), NULLIF(REPLACE(plainto_tsquery('english', $2)::text, '&', '|'), '')::tsquery), 0) * 2.0) ${exactNameScoreExpr}) AS hybrid_score
186
+ COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), to_tsquery('english', $2)), 0) AS keyword_score,
187
+ ((1 - (embedding <=> $1::vector)) + (COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), to_tsquery('english', $2)), 0) * 2.0) ${exactNameScoreExpr}) AS hybrid_score
178
188
  FROM "${table}" t
179
189
  ORDER BY hybrid_score DESC
180
190
  LIMIT 50
181
191
  `;
182
- params = [vectorLiteral, queryText];
192
+ params = [vectorLiteral, cleanedText];
183
193
  } else {
184
194
  // Fallback to Vector-only Search
185
195
  sqlQuery = `