@retrivora-ai/rag-engine 1.8.9 → 1.9.0

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.
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { CSSProperties, MouseEvent, ReactNode } from 'react';
3
- import { P as Product, U as UIConfig, R as RagMessage, V as VectorMatch, O as ObservabilityTrace, a as UseRagChatOptions, b as UseRagChatReturn } from './ILLMProvider-CbUtvWAW.mjs';
4
- export { C as ChatMessage, c as ChatOptions, d as ChatResponse, E as EmbedOptions, e as EmbeddingConfig, f as EmbeddingProvider, I as ILLMProvider, g as IngestDocument, L as LLMConfig, h as LLMProvider, i as LatencyBreakdown, j as RAGConfig, k as RagConfig, l as RetrievedChunk, T as TokenUsage, m as UpsertDocument, n as VectorDBConfig, o as VectorDBProvider } from './ILLMProvider-CbUtvWAW.mjs';
3
+ import { P as Product, U as UIConfig, R as RagMessage, V as VectorMatch, O as ObservabilityTrace, a as UseRagChatOptions, b as UseRagChatReturn } from './ILLMProvider-BOJFz3Na.mjs';
4
+ export { C as ChatMessage, c as ChatOptions, d as ChatResponse, E as EmbedOptions, e as EmbeddingConfig, f as EmbeddingProvider, I as ILLMProvider, g as IngestDocument, L as LLMConfig, h as LLMProvider, i as LatencyBreakdown, j as RAGConfig, k as RagConfig, l as RetrievedChunk, T as TokenUsage, m as UpsertDocument, n as VectorDBConfig, o as VectorDBProvider } from './ILLMProvider-BOJFz3Na.mjs';
5
5
  export { C as Chunk, a as ChunkOptions } from './DocumentChunker-Dh9TvmGG.mjs';
6
6
 
7
7
  type ChatViewportSize = 'compact' | 'medium' | 'large';
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { CSSProperties, MouseEvent, ReactNode } from 'react';
3
- import { P as Product, U as UIConfig, R as RagMessage, V as VectorMatch, O as ObservabilityTrace, a as UseRagChatOptions, b as UseRagChatReturn } from './ILLMProvider-CbUtvWAW.js';
4
- export { C as ChatMessage, c as ChatOptions, d as ChatResponse, E as EmbedOptions, e as EmbeddingConfig, f as EmbeddingProvider, I as ILLMProvider, g as IngestDocument, L as LLMConfig, h as LLMProvider, i as LatencyBreakdown, j as RAGConfig, k as RagConfig, l as RetrievedChunk, T as TokenUsage, m as UpsertDocument, n as VectorDBConfig, o as VectorDBProvider } from './ILLMProvider-CbUtvWAW.js';
3
+ import { P as Product, U as UIConfig, R as RagMessage, V as VectorMatch, O as ObservabilityTrace, a as UseRagChatOptions, b as UseRagChatReturn } from './ILLMProvider-BOJFz3Na.js';
4
+ export { C as ChatMessage, c as ChatOptions, d as ChatResponse, E as EmbedOptions, e as EmbeddingConfig, f as EmbeddingProvider, I as ILLMProvider, g as IngestDocument, L as LLMConfig, h as LLMProvider, i as LatencyBreakdown, j as RAGConfig, k as RagConfig, l as RetrievedChunk, T as TokenUsage, m as UpsertDocument, n as VectorDBConfig, o as VectorDBProvider } from './ILLMProvider-BOJFz3Na.js';
5
5
  export { C as Chunk, a as ChunkOptions } from './DocumentChunker-Dh9TvmGG.js';
6
6
 
7
7
  type ChatViewportSize = 'compact' | 'medium' | 'large';
package/dist/server.d.mts CHANGED
@@ -1,7 +1,7 @@
1
- import { n as VectorDBConfig, L as LLMConfig, e as EmbeddingConfig, k as RagConfig, I as ILLMProvider, g as IngestDocument, C as ChatMessage, d as ChatResponse, p as RetrievalResult, m as UpsertDocument, V as VectorMatch, G as GraphDBConfig, q as GraphNode, r as Edge, s as GraphSearchResult, o as VectorDBProvider, h as LLMProvider, f as EmbeddingProvider, j as RAGConfig, U as UIConfig, c as ChatOptions, E as EmbedOptions } from './ILLMProvider-CbUtvWAW.mjs';
1
+ import { n as VectorDBConfig, L as LLMConfig, e as EmbeddingConfig, k as RagConfig, I as ILLMProvider, g as IngestDocument, C as ChatMessage, d as ChatResponse, p as RetrievalResult, m as UpsertDocument, V as VectorMatch, G as GraphDBConfig, q as GraphNode, r as Edge, s as GraphSearchResult, o as VectorDBProvider, h as LLMProvider, f as EmbeddingProvider, j as RAGConfig, U as UIConfig, c as ChatOptions, E as EmbedOptions } from './ILLMProvider-BOJFz3Na.mjs';
2
2
  export { C as Chunk, a as ChunkOptions, D as DocumentChunker } from './DocumentChunker-Dh9TvmGG.mjs';
3
- import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-c_y_5qdw.mjs';
4
- export { C as ConfigValidator, V as ValidationError, b as VectorPlugin, c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, j as sseTextFrame } from './index-c_y_5qdw.mjs';
3
+ import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-D3V9Et2M.mjs';
4
+ export { C as ConfigValidator, V as ValidationError, b as VectorPlugin, c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, j as sseTextFrame } from './index-D3V9Et2M.mjs';
5
5
  import 'next/server';
6
6
 
7
7
  /**
package/dist/server.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { n as VectorDBConfig, L as LLMConfig, e as EmbeddingConfig, k as RagConfig, I as ILLMProvider, g as IngestDocument, C as ChatMessage, d as ChatResponse, p as RetrievalResult, m as UpsertDocument, V as VectorMatch, G as GraphDBConfig, q as GraphNode, r as Edge, s as GraphSearchResult, o as VectorDBProvider, h as LLMProvider, f as EmbeddingProvider, j as RAGConfig, U as UIConfig, c as ChatOptions, E as EmbedOptions } from './ILLMProvider-CbUtvWAW.js';
1
+ import { n as VectorDBConfig, L as LLMConfig, e as EmbeddingConfig, k as RagConfig, I as ILLMProvider, g as IngestDocument, C as ChatMessage, d as ChatResponse, p as RetrievalResult, m as UpsertDocument, V as VectorMatch, G as GraphDBConfig, q as GraphNode, r as Edge, s as GraphSearchResult, o as VectorDBProvider, h as LLMProvider, f as EmbeddingProvider, j as RAGConfig, U as UIConfig, c as ChatOptions, E as EmbedOptions } from './ILLMProvider-BOJFz3Na.js';
2
2
  export { C as Chunk, a as ChunkOptions, D as DocumentChunker } from './DocumentChunker-Dh9TvmGG.js';
3
- import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-DgzcnqZs.js';
4
- export { C as ConfigValidator, V as ValidationError, b as VectorPlugin, c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, j as sseTextFrame } from './index-DgzcnqZs.js';
3
+ import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-BwpcaziY.js';
4
+ export { C as ConfigValidator, V as ValidationError, b as VectorPlugin, c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, j as sseTextFrame } from './index-BwpcaziY.js';
5
5
  import 'next/server';
6
6
 
7
7
  /**
package/dist/server.js CHANGED
@@ -374,12 +374,10 @@ var init_MultiTablePostgresProvider = __esm({
374
374
  embedding VECTOR(${this.dimensions})
375
375
  )
376
376
  `);
377
- const metric = this.config.distanceMetric || "cosine";
378
- const indexOps = metric === "euclidean" ? "vector_l2_ops" : metric === "dotproduct" ? "vector_ip_ops" : "vector_cosine_ops";
379
377
  await client.query(`
380
378
  CREATE INDEX IF NOT EXISTS ${this.uploadTable}_embedding_idx
381
379
  ON ${this.uploadTable}
382
- USING hnsw (embedding ${indexOps})
380
+ USING hnsw (embedding vector_cosine_ops)
383
381
  `);
384
382
  const res = await client.query(`
385
383
  SELECT table_name
@@ -441,12 +439,10 @@ var init_MultiTablePostgresProvider = __esm({
441
439
  )
442
440
  `;
443
441
  await client.query(createTableSql);
444
- const metric = this.config.distanceMetric || "cosine";
445
- const indexOps = metric === "euclidean" ? "vector_l2_ops" : metric === "dotproduct" ? "vector_ip_ops" : "vector_cosine_ops";
446
442
  await client.query(`
447
443
  CREATE INDEX IF NOT EXISTS "${tableName}_embedding_idx"
448
444
  ON "${tableName}"
449
- USING hnsw (embedding ${indexOps})
445
+ USING hnsw (embedding vector_cosine_ops)
450
446
  `);
451
447
  if (!this.tables.includes(tableName)) {
452
448
  this.tables.push(tableName);
@@ -528,8 +524,6 @@ var init_MultiTablePostgresProvider = __esm({
528
524
  try {
529
525
  let sqlQuery = "";
530
526
  let params = [];
531
- const metric = this.config.distanceMetric || "cosine";
532
- const scoreExpr = metric === "euclidean" ? `1 / (1 + (embedding <-> $1::vector))` : metric === "dotproduct" ? `(embedding <#> $1::vector) * -1` : `1 - (embedding <=> $1::vector)`;
533
527
  if (queryText) {
534
528
  const hasEntityHints = entityHints.length > 0;
535
529
  const exactNameScoreExpr = hasEntityHints ? `+ (
@@ -542,9 +536,9 @@ var init_MultiTablePostgresProvider = __esm({
542
536
  ) * 3.0` : "";
543
537
  sqlQuery = `
544
538
  SELECT *,
545
- (${scoreExpr}) AS vector_score,
539
+ (1 - (embedding <=> $1::vector)) AS vector_score,
546
540
  COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), to_tsquery('english', $2)), 0) AS keyword_score,
547
- ((${scoreExpr}) + (COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), to_tsquery('english', $2)), 0) * 2.0) ${exactNameScoreExpr}) AS hybrid_score
541
+ ((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
548
542
  FROM "${table}" t
549
543
  ORDER BY hybrid_score DESC
550
544
  LIMIT 50
@@ -553,7 +547,7 @@ var init_MultiTablePostgresProvider = __esm({
553
547
  } else {
554
548
  sqlQuery = `
555
549
  SELECT *,
556
- (${scoreExpr}) AS hybrid_score
550
+ (1 - (embedding <=> $1::vector)) AS hybrid_score
557
551
  FROM "${table}" t
558
552
  ORDER BY hybrid_score DESC
559
553
  LIMIT 50
@@ -1027,13 +1021,11 @@ var init_QdrantProvider = __esm({
1027
1021
  if (import_axios4.default.isAxiosError(err) && ((_a = err.response) == null ? void 0 : _a.status) === 404) {
1028
1022
  const opts = this.config.options;
1029
1023
  const dimensionsForCreate = opts.dimensions || 1536;
1030
- const metric = this.config.distanceMetric || "cosine";
1031
- const distance = metric === "euclidean" ? "Euclid" : metric === "dotproduct" ? "Dot" : "Cosine";
1032
1024
  console.log(`[QdrantProvider] \u23F3 Creating collection "${this.indexName}" (dimensions: ${dimensionsForCreate})...`);
1033
1025
  await this.http.put(`/collections/${this.indexName}`, {
1034
1026
  vectors: {
1035
1027
  size: dimensionsForCreate,
1036
- distance
1028
+ distance: "Cosine"
1037
1029
  }
1038
1030
  });
1039
1031
  console.log(`[QdrantProvider] \u2705 Created collection "${this.indexName}"`);
@@ -1211,12 +1203,9 @@ var init_ChromaDBProvider = __esm({
1211
1203
  console.log(`[ChromaDBProvider] \u2705 Collection "${this.indexName}" found (id: ${this.collectionId})`);
1212
1204
  } catch (err) {
1213
1205
  if (import_axios5.default.isAxiosError(err) && ((_a = err.response) == null ? void 0 : _a.status) === 404) {
1214
- const metric = this.config.distanceMetric || "cosine";
1215
- const space = metric === "euclidean" ? "l2" : metric === "dotproduct" ? "ip" : "cosine";
1216
1206
  console.log(`[ChromaDBProvider] \u23F3 Collection "${this.indexName}" not found. Creating...`);
1217
1207
  const { data } = await this.http.post("/api/v1/collections", {
1218
- name: this.indexName,
1219
- metadata: { "hnsw:space": space }
1208
+ name: this.indexName
1220
1209
  });
1221
1210
  this.collectionId = data.id;
1222
1211
  console.log(`[ChromaDBProvider] \u2705 Created collection "${this.indexName}" (id: ${this.collectionId})`);
@@ -4253,20 +4242,18 @@ var UITransformer = class {
4253
4242
  }
4254
4243
  const isStockRequest = this.isStockQuery(userQuery);
4255
4244
  const filteredData = isStockRequest ? retrievedData.filter((item) => this.determineStockStatus(item)) : retrievedData;
4256
- const groupByField = this.determineGroupByField(userQuery, filteredData);
4257
- const categories = this.detectCategories(filteredData, groupByField);
4245
+ const categories = this.detectCategories(filteredData);
4258
4246
  const hasProducts = filteredData.some((item) => this.isProductData(item));
4259
4247
  const isTimeSeries = filteredData.some((item) => this.isTimeSeriesData(item));
4260
4248
  const isTrendQuery = this.isTrendQuery(userQuery);
4261
4249
  if (isTrendQuery && isTimeSeries) {
4262
4250
  return this.transformToLineChart(filteredData);
4263
4251
  }
4264
- const explicitChartRequest = this.isExplicitChartQuery(userQuery);
4265
- if (hasProducts && !explicitChartRequest && !this.shouldShowCategoryChart(userQuery)) {
4252
+ if (hasProducts && !this.shouldShowCategoryChart(userQuery, categories)) {
4266
4253
  return this.transformToProductCarousel(filteredData, config, trainedSchema);
4267
4254
  }
4268
- if (explicitChartRequest || categories.length > 1 && this.shouldShowCategoryChart(userQuery)) {
4269
- return this.transformToPieChart(filteredData, groupByField);
4255
+ if (categories.length > 1 && this.shouldShowCategoryChart(userQuery, categories)) {
4256
+ return this.transformToPieChart(filteredData);
4270
4257
  }
4271
4258
  if (hasProducts) {
4272
4259
  return this.transformToProductCarousel(filteredData, config, trainedSchema);
@@ -4291,12 +4278,11 @@ var UITransformer = class {
4291
4278
  /**
4292
4279
  * Transform data to pie chart format
4293
4280
  */
4294
- static transformToPieChart(data, groupByField) {
4295
- let categories = this.detectCategories(data, groupByField);
4296
- if (categories.length === 0) categories = ["All Data"];
4297
- const categoryData = this.aggregateByCategory(data, categories, groupByField);
4281
+ static transformToPieChart(data) {
4282
+ const categories = this.detectCategories(data);
4283
+ const categoryData = this.aggregateByCategory(data, categories);
4298
4284
  const pieData = Object.entries(categoryData).map(([label, count]) => {
4299
- const { inStockCount, outOfStockCount } = this.calculateStockCounts(label, data, groupByField);
4285
+ const { inStockCount, outOfStockCount } = this.calculateStockCounts(label, data);
4300
4286
  return {
4301
4287
  label,
4302
4288
  value: count,
@@ -4306,7 +4292,7 @@ var UITransformer = class {
4306
4292
  });
4307
4293
  return {
4308
4294
  type: "pie_chart",
4309
- title: `Distribution by ${groupByField.charAt(0).toUpperCase() + groupByField.slice(1)}`,
4295
+ title: "Distribution by Category",
4310
4296
  description: `Showing breakdown across ${categories.length} categories`,
4311
4297
  data: pieData
4312
4298
  };
@@ -4529,11 +4515,10 @@ var UITransformer = class {
4529
4515
  });
4530
4516
  return hasTimeKeyword || hasValidDateValue;
4531
4517
  }
4532
- static isExplicitChartQuery(query) {
4533
- const normalized = query.toLowerCase();
4534
- return normalized.includes("pie chart") || normalized.includes("piechart") || normalized.includes("bar chart") || normalized.includes("barchart") || normalized.includes("radar chart");
4535
- }
4536
- static shouldShowCategoryChart(query) {
4518
+ static shouldShowCategoryChart(query, categories) {
4519
+ if (categories.length < 2) {
4520
+ return false;
4521
+ }
4537
4522
  const normalized = query.toLowerCase();
4538
4523
  const chartKeywords = [
4539
4524
  "distribution",
@@ -4546,11 +4531,7 @@ var UITransformer = class {
4546
4531
  "segmentation",
4547
4532
  "split",
4548
4533
  "category breakdown",
4549
- "category distribution",
4550
- "pie chart",
4551
- "piechart",
4552
- "bar chart",
4553
- "barchart"
4534
+ "category distribution"
4554
4535
  ];
4555
4536
  return chartKeywords.some((keyword) => normalized.includes(keyword));
4556
4537
  }
@@ -4626,67 +4607,44 @@ var UITransformer = class {
4626
4607
  return null;
4627
4608
  }
4628
4609
  /**
4629
- * Helper: Dynamically determine what field to group by based on user query
4630
- */
4631
- static determineGroupByField(query, data) {
4632
- const normalized = query.toLowerCase();
4633
- const match = normalized.match(/(?:by|across|per|based on)\s+([a-zA-Z]+)/i);
4634
- let targetField = "category";
4635
- if (match && match[1]) {
4636
- let field = match[1].toLowerCase();
4637
- if (field.endsWith("ies")) field = field.replace(/ies$/, "y");
4638
- else if (field.endsWith("s") && field !== "status") field = field.slice(0, -1);
4639
- const stopWords = ["the", "all", "different", "various", "some", "these", "those"];
4640
- if (!stopWords.includes(field)) {
4641
- targetField = field;
4642
- }
4643
- }
4644
- const hasTargetField = data.some((d) => d.metadata && d.metadata[targetField] !== void 0);
4645
- if (!hasTargetField && targetField === "category") {
4646
- if (data.some((d) => d.metadata && d.metadata["type"] !== void 0)) return "type";
4647
- if (data.some((d) => d.metadata && d.metadata["brand"] !== void 0)) return "brand";
4648
- }
4649
- return targetField;
4650
- }
4651
- /**
4652
- * Helper: Detect grouping values dynamically
4610
+ * Helper: Detect categories in data
4653
4611
  */
4654
- static detectCategories(data, groupByField) {
4612
+ static detectCategories(data) {
4655
4613
  const categories = /* @__PURE__ */ new Set();
4656
4614
  data.forEach((item) => {
4657
4615
  const meta = item.metadata || {};
4658
- if (meta[groupByField] !== void 0) {
4659
- const val = meta[groupByField];
4660
- if (Array.isArray(val)) val.forEach((v) => categories.add(String(v)));
4661
- else categories.add(String(val));
4662
- } else if (groupByField === "category") {
4663
- if (meta.type) categories.add(String(meta.type));
4664
- if (meta.tag) {
4665
- const tags = Array.isArray(meta.tag) ? meta.tag : [meta.tag];
4666
- tags.forEach((t) => categories.add(String(t)));
4667
- }
4668
- const categoryMatch = item.content.match(/(?:Category|Type|Class):\s*([^\n]+)/i);
4669
- if (categoryMatch) categories.add(categoryMatch[1].trim());
4616
+ if (meta.category) {
4617
+ categories.add(String(meta.category));
4618
+ }
4619
+ if (meta.type) {
4620
+ categories.add(String(meta.type));
4621
+ }
4622
+ if (meta.tag) {
4623
+ const tags = Array.isArray(meta.tag) ? meta.tag : [meta.tag];
4624
+ tags.forEach((t) => categories.add(String(t)));
4625
+ }
4626
+ const contentCategories = Array.from(new Set(
4627
+ Array.from(item.content.matchAll(/^\s*([^:\n]+):\s*(?:•|\*|-)*/gm)).map((match) => match[1].trim()).filter(Boolean)
4628
+ ));
4629
+ contentCategories.forEach((category) => categories.add(category));
4630
+ const categoryMatch = item.content.match(/(?:Category|Type|Class):\s*([^\n]+)/i);
4631
+ if (categoryMatch) {
4632
+ categories.add(categoryMatch[1].trim());
4670
4633
  }
4671
4634
  });
4672
4635
  return Array.from(categories);
4673
4636
  }
4674
4637
  /**
4675
- * Helper: Aggregate data dynamically
4638
+ * Helper: Aggregate data by category
4676
4639
  */
4677
- static aggregateByCategory(data, categories, groupByField) {
4640
+ static aggregateByCategory(data, categories) {
4678
4641
  const result = {};
4679
4642
  categories.forEach((cat) => {
4680
4643
  result[cat] = 0;
4681
4644
  });
4682
4645
  data.forEach((item) => {
4683
4646
  const meta = item.metadata || {};
4684
- let itemCategory = "Other";
4685
- if (meta[groupByField] !== void 0) {
4686
- itemCategory = String(meta[groupByField]);
4687
- } else if (groupByField === "category" && meta.type) {
4688
- itemCategory = String(meta.type);
4689
- }
4647
+ const itemCategory = meta.category || meta.type || "Other";
4690
4648
  if (Object.prototype.hasOwnProperty.call(result, itemCategory)) {
4691
4649
  result[itemCategory]++;
4692
4650
  } else {
@@ -4736,19 +4694,14 @@ var UITransformer = class {
4736
4694
  });
4737
4695
  }
4738
4696
  /**
4739
- * Helper: Calculate stock counts dynamically
4697
+ * Helper: Calculate stock counts by category
4740
4698
  */
4741
- static calculateStockCounts(category, data, groupByField) {
4699
+ static calculateStockCounts(category, data) {
4742
4700
  let inStock = 0;
4743
4701
  let outOfStock = 0;
4744
4702
  data.forEach((d) => {
4745
4703
  const meta = d.metadata || {};
4746
- let itemCategory = "Other";
4747
- if (meta[groupByField] !== void 0) {
4748
- itemCategory = String(meta[groupByField]);
4749
- } else if (groupByField === "category" && meta.type) {
4750
- itemCategory = String(meta.type);
4751
- }
4704
+ const itemCategory = meta.category || meta.type || "Other";
4752
4705
  if (itemCategory === category) {
4753
4706
  if (this.determineStockStatus(d)) {
4754
4707
  inStock++;
@@ -4873,13 +4826,12 @@ DATA SHAPE per type:
4873
4826
  - text: { "content": "<prose answer>" }
4874
4827
 
4875
4828
  DECISION RULES (follow strictly):
4876
- 1. IF the user explicitly asks for a "pie chart", "bar chart", or "table", you MUST output that exact type. Do not deviate from their request.
4877
- 2. bar_chart \u2192 comparing quantities across categories (e.g. sales by region, price by product). Use this when there is only ONE value per category.
4878
- 3. line_chart \u2192 trends or changes over time (dates, months, years, sequential events)
4879
- 4. pie_chart \u2192 proportional breakdown or percentage distribution
4880
- 5. radar_chart \u2192 comparing 2 or more products across MULTIPLE attributes.
4881
- 6. table \u2192 multi-field structured records where each item has \u2265 3 attributes
4882
- 7. text \u2192 conversational or free-form answers where no chart adds value
4829
+ 1. bar_chart \u2192 comparing quantities across categories (e.g. sales by region, price by product). Use this when there is only ONE value per category.
4830
+ 2. line_chart \u2192 trends or changes over time (dates, months, years, sequential events)
4831
+ 3. pie_chart \u2192 proportional breakdown or percentage distribution
4832
+ 4. radar_chart \u2192 comparing 2 or more products across MULTIPLE attributes (e.g. comparing features, ratings, or characteristics of 2 specific products). If the user asks to "compare" products and the data contains multiple dimensions or ratings for them, you MUST use this.
4833
+ 5. table \u2192 multi-field structured records where each item has \u2265 3 attributes
4834
+ 6. text \u2192 conversational or free-form answers where no chart adds value
4883
4835
 
4884
4836
  IMPORTANT:
4885
4837
  - Aggregate numeric values from the raw data \u2014 do not pass raw object arrays as data.
@@ -6037,12 +5989,10 @@ var PostgreSQLProvider = class extends BaseVectorProvider {
6037
5989
  embedding VECTOR(${this.dimensions})
6038
5990
  )
6039
5991
  `);
6040
- const metric = this.config.distanceMetric || "cosine";
6041
- const indexOps = metric === "euclidean" ? "vector_l2_ops" : metric === "dotproduct" ? "vector_ip_ops" : "vector_cosine_ops";
6042
5992
  await client.query(`
6043
5993
  CREATE INDEX IF NOT EXISTS ${this.tableName}_embedding_idx
6044
5994
  ON ${this.tableName}
6045
- USING hnsw (embedding ${indexOps})
5995
+ USING hnsw (embedding vector_cosine_ops)
6046
5996
  `);
6047
5997
  } finally {
6048
5998
  client.release();
@@ -6114,14 +6064,11 @@ var PostgreSQLProvider = class extends BaseVectorProvider {
6114
6064
  try {
6115
6065
  const efSearch = this.config.options.efSearch || Math.max(topK * 10, 40);
6116
6066
  await client.query(`SET LOCAL hnsw.ef_search = ${efSearch}`);
6117
- const metric = this.config.distanceMetric || "cosine";
6118
- const queryOp = metric === "euclidean" ? "<->" : metric === "dotproduct" ? "<#>" : "<=>";
6119
- const scoreExpr = metric === "euclidean" ? `1 / (1 + (embedding <-> $1::vector))` : metric === "dotproduct" ? `(embedding <#> $1::vector) * -1` : `1 - (embedding <=> $1::vector)`;
6120
6067
  const result = await client.query(
6121
- `SELECT id, content, metadata, ${scoreExpr} AS score
6068
+ `SELECT id, content, metadata, 1 - (embedding <=> $1::vector) AS score
6122
6069
  FROM ${this.tableName}
6123
6070
  ${whereClause}
6124
- ORDER BY embedding ${queryOp} $1::vector
6071
+ ORDER BY embedding <=> $1::vector
6125
6072
  LIMIT $2`,
6126
6073
  params
6127
6074
  );