@retrivora-ai/rag-engine 1.8.1 → 1.8.2

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.
Files changed (55) hide show
  1. package/dist/{ILLMProvider-BfRgI1Xh.d.mts → ILLMProvider-BOJFz3Na.d.mts} +47 -1
  2. package/dist/{ILLMProvider-BfRgI1Xh.d.ts → ILLMProvider-BOJFz3Na.d.ts} +47 -1
  3. package/dist/{MultiTablePostgresProvider-YY7LPNJK.mjs → MultiTablePostgresProvider-ZLGSKTJR.mjs} +1 -1
  4. package/dist/chunk-ICKRMZQK.mjs +76 -0
  5. package/dist/{chunk-BFYLQYQU.mjs → chunk-LZVVLSDN.mjs} +192 -100
  6. package/dist/{chunk-R3RGUMHE.mjs → chunk-OZFBG4BA.mjs} +121 -48
  7. package/dist/handlers/index.d.mts +2 -2
  8. package/dist/handlers/index.d.ts +2 -2
  9. package/dist/handlers/index.js +368 -147
  10. package/dist/handlers/index.mjs +4 -1
  11. package/dist/{index-BV0z5mb6.d.mts → index-BwpcaziY.d.ts} +4 -2
  12. package/dist/{index-1Z4GuYBi.d.ts → index-D3V9Et2M.d.mts} +4 -2
  13. package/dist/index.d.mts +23 -3
  14. package/dist/index.d.ts +23 -3
  15. package/dist/index.js +1143 -790
  16. package/dist/index.mjs +1065 -770
  17. package/dist/server.d.mts +15 -25
  18. package/dist/server.d.ts +15 -25
  19. package/dist/server.js +366 -147
  20. package/dist/server.mjs +3 -2
  21. package/package.json +4 -2
  22. package/src/app/api/upload/route.ts +4 -0
  23. package/src/app/constants.tsx +2 -2
  24. package/src/app/page.tsx +12 -321
  25. package/src/components/AmbientBackground.tsx +29 -0
  26. package/src/components/ArchitectureCard.tsx +17 -0
  27. package/src/components/ArchitectureCardsSection.tsx +15 -0
  28. package/src/components/ChatWindow.tsx +32 -0
  29. package/src/components/CodeViewer.tsx +51 -0
  30. package/src/components/ConfigProvider.tsx +1 -0
  31. package/src/components/DocViewer.tsx +37 -0
  32. package/src/components/DocumentUpload.tsx +44 -1
  33. package/src/components/Documentation.tsx +58 -0
  34. package/src/components/DynamicChart.tsx +27 -2
  35. package/src/components/Hero.tsx +59 -0
  36. package/src/components/HourglassLoader.tsx +87 -0
  37. package/src/components/Lifecycle.tsx +37 -0
  38. package/src/components/MarkdownComponents.tsx +140 -0
  39. package/src/components/MessageBubble.tsx +88 -1010
  40. package/src/components/Navbar.tsx +55 -0
  41. package/src/components/ObservabilityPanel.tsx +374 -0
  42. package/src/components/ProductCard.tsx +3 -1
  43. package/src/components/UIDispatcher.tsx +344 -0
  44. package/src/components/VisualizationRenderer.tsx +48 -26
  45. package/src/core/Pipeline.ts +186 -76
  46. package/src/handlers/index.ts +72 -12
  47. package/src/hooks/useRagChat.ts +19 -9
  48. package/src/index.ts +9 -1
  49. package/src/providers/vectordb/MultiTablePostgresProvider.ts +150 -64
  50. package/src/types/chat.ts +2 -0
  51. package/src/types/index.ts +52 -0
  52. package/src/types/props.ts +9 -1
  53. package/src/utils/ProductExtractor.ts +347 -0
  54. package/src/utils/UITransformer.ts +4 -53
  55. package/src/utils/synonyms.ts +78 -0
@@ -1,3 +1,6 @@
1
+ import {
2
+ resolveMetadataValue
3
+ } from "./chunk-ICKRMZQK.mjs";
1
4
  import {
2
5
  buildPayload,
3
6
  mergeDefined,
@@ -1348,7 +1351,7 @@ var ProviderRegistry = class {
1348
1351
  }
1349
1352
  case "pgvector":
1350
1353
  case "postgresql": {
1351
- const { MultiTablePostgresProvider } = await import("./MultiTablePostgresProvider-YY7LPNJK.mjs");
1354
+ const { MultiTablePostgresProvider } = await import("./MultiTablePostgresProvider-ZLGSKTJR.mjs");
1352
1355
  return MultiTablePostgresProvider;
1353
1356
  }
1354
1357
  case "mongodb": {
@@ -2380,28 +2383,6 @@ var UITransformer = class {
2380
2383
  data: pieData
2381
2384
  };
2382
2385
  }
2383
- /**
2384
- * Transform data to bar chart format
2385
- */
2386
- static transformToBarChart(data) {
2387
- const categories = this.detectCategories(data);
2388
- const categoryData = this.aggregateByCategory(data, categories);
2389
- const barData = Object.entries(categoryData).map(([category, value]) => {
2390
- const { inStockCount, outOfStockCount } = this.calculateStockCounts(category, data);
2391
- return {
2392
- category,
2393
- value,
2394
- inStockCount,
2395
- outOfStockCount
2396
- };
2397
- });
2398
- return {
2399
- type: "bar_chart",
2400
- title: "Comparison by Category",
2401
- description: `Comparing ${categories.length} categories`,
2402
- data: barData
2403
- };
2404
- }
2405
2386
  /**
2406
2387
  * Transform data to line chart format
2407
2388
  */
@@ -2680,15 +2661,7 @@ var UITransformer = class {
2680
2661
  const trainedKey = trainedSchema[uiKey];
2681
2662
  if (trainedKey && meta[trainedKey] !== void 0) return meta[trainedKey];
2682
2663
  }
2683
- const synonyms = this.SYNONYMS[uiKey] || [];
2684
- const searchKeys = [uiKey, ...synonyms].map((k) => k.toLowerCase());
2685
- const foundDirectKey = Object.keys(meta).find((k) => searchKeys.includes(k.toLowerCase()));
2686
- if (foundDirectKey) return meta[foundDirectKey];
2687
- const foundPartialKey = Object.keys(meta).find((k) => {
2688
- const keyLow = k.toLowerCase();
2689
- return searchKeys.some((sk) => keyLow.includes(sk) || sk.includes(keyLow));
2690
- });
2691
- return foundPartialKey ? meta[foundPartialKey] : void 0;
2664
+ return resolveMetadataValue(meta, uiKey);
2692
2665
  }
2693
2666
  static extractProductInfo(item, config, trainedSchema) {
2694
2667
  const meta = item.metadata || {};
@@ -2758,7 +2731,7 @@ var UITransformer = class {
2758
2731
  data.forEach((item) => {
2759
2732
  const meta = item.metadata || {};
2760
2733
  const itemCategory = meta.category || meta.type || "Other";
2761
- if (result.hasOwnProperty(itemCategory)) {
2734
+ if (Object.prototype.hasOwnProperty.call(result, itemCategory)) {
2762
2735
  result[itemCategory]++;
2763
2736
  } else {
2764
2737
  result["Other"] = (result["Other"] || 0) + 1;
@@ -2979,18 +2952,6 @@ IMPORTANT:
2979
2952
  return JSON.stringify(partial, null, 2) + "\n// ... truncated";
2980
2953
  }
2981
2954
  };
2982
- /**
2983
- * Central dictionary of common synonyms for UI properties.
2984
- * This allows the system to be schema-agnostic by guessing field names.
2985
- */
2986
- UITransformer.SYNONYMS = {
2987
- name: ["product", "item", "title", "label", "heading", "subject"],
2988
- price: ["cost", "amount", "msrp", "price", "rate", "value", "price_usd"],
2989
- brand: ["manufacturer", "vendor", "make", "company", "brand_name", "supplier"],
2990
- image: ["imageUrl", "thumbnail", "img", "url", "photo", "picture", "media", "image_url", "main_image", "product_image", "thumb"],
2991
- stock: ["inventory", "quantity", "count", "availability", "stock_level", "inStock", "is_available"],
2992
- description: ["summary", "content", "body", "text", "info", "details"]
2993
- };
2994
2955
 
2995
2956
  // src/utils/SchemaMapper.ts
2996
2957
  var SchemaMapper = class {
@@ -3111,6 +3072,57 @@ var LRUEmbeddingCache = class {
3111
3072
  return this.cache.size;
3112
3073
  }
3113
3074
  };
3075
+ function estimateTokens(text) {
3076
+ return Math.ceil(text.length / 4);
3077
+ }
3078
+ var MODEL_COST_PER_1K = {
3079
+ "gpt-4o": { input: 25e-4, output: 0.01 },
3080
+ "gpt-4o-mini": { input: 15e-5, output: 6e-4 },
3081
+ "gpt-4-turbo": { input: 0.01, output: 0.03 },
3082
+ "gpt-3.5-turbo": { input: 5e-4, output: 15e-4 },
3083
+ "claude-3-5-sonnet": { input: 3e-3, output: 0.015 },
3084
+ "claude-3-haiku": { input: 25e-5, output: 125e-5 },
3085
+ "gemini-1.5-flash": { input: 75e-6, output: 3e-4 },
3086
+ "gemini-1.5-pro": { input: 125e-5, output: 5e-3 }
3087
+ };
3088
+ function estimateCostUsd(promptTokens, completionTokens, model) {
3089
+ if (!model) return void 0;
3090
+ const key = Object.keys(MODEL_COST_PER_1K).find((k) => model.toLowerCase().includes(k));
3091
+ if (!key) return void 0;
3092
+ const prices = MODEL_COST_PER_1K[key];
3093
+ return promptTokens / 1e3 * prices.input + completionTokens / 1e3 * prices.output;
3094
+ }
3095
+ async function scoreHallucination(llm, answer, context) {
3096
+ const maxContextChars = 3e3;
3097
+ const truncatedContext = context.length > maxContextChars ? context.slice(0, maxContextChars) + "\n...[truncated]" : context;
3098
+ const prompt = `You are an AI quality checker. Given the CONTEXT retrieved from a knowledge base and the ANSWER generated from it, rate how well-grounded the answer is.
3099
+
3100
+ CONTEXT:
3101
+ ${truncatedContext}
3102
+
3103
+ ANSWER:
3104
+ ${answer}
3105
+
3106
+ Return ONLY a valid JSON object with no markdown fences:
3107
+ {"score": <float 0-1>, "reason": "<one sentence>"}
3108
+
3109
+ Where score 0 = fully grounded in context, score 1 = likely hallucinated or unsupported.`;
3110
+ try {
3111
+ const raw = await llm.chat(
3112
+ [{ role: "user", content: prompt }],
3113
+ "",
3114
+ { temperature: 0, maxTokens: 120 }
3115
+ );
3116
+ const jsonMatch = raw.match(/\{[\s\S]*\}/);
3117
+ if (!jsonMatch) return void 0;
3118
+ const parsed = JSON.parse(jsonMatch[0]);
3119
+ if (typeof parsed.score === "number" && typeof parsed.reason === "string") {
3120
+ return { score: Math.min(1, Math.max(0, parsed.score)), reason: parsed.reason };
3121
+ }
3122
+ } catch (e) {
3123
+ }
3124
+ return void 0;
3125
+ }
3114
3126
  var Pipeline = class {
3115
3127
  constructor(config) {
3116
3128
  this.config = config;
@@ -3137,8 +3149,7 @@ var Pipeline = class {
3137
3149
  async initialize() {
3138
3150
  var _a;
3139
3151
  if (this.initialised) return;
3140
- const chartInstruction = `
3141
- You are a helpful product assistant. Use the provided context to answer questions accurately.
3152
+ const chartInstruction = `You are a helpful product assistant. Use the provided context to answer questions accurately.
3142
3153
 
3143
3154
  ### UI STYLE RULES (CRITICAL):
3144
3155
  - NEVER generate markdown tables. If you do, the UI will break.
@@ -3152,7 +3163,6 @@ You are a helpful product assistant. Use the provided context to answer question
3152
3163
  - Do NOT try to format product lists as tables.
3153
3164
  `;
3154
3165
  this.config.llm.systemPrompt = chartInstruction;
3155
- console.log(`[Pipeline] Initializing with provider: ${this.config.vectorDb.provider}...`);
3156
3166
  this.vectorDB = await ProviderRegistry.createVectorProvider(this.config.vectorDb);
3157
3167
  const { llmProvider, embeddingProvider } = await EmbeddingStrategyResolver.resolve(
3158
3168
  this.config.llm,
@@ -3174,7 +3184,6 @@ You are a helpful product assistant. Use the provided context to answer question
3174
3184
  }
3175
3185
  /**
3176
3186
  * Ingest documents with automatic chunking, embedding, and batch upsert.
3177
- * Handles retries for transient failures.
3178
3187
  */
3179
3188
  async ingest(documents, namespace) {
3180
3189
  await this.initialize();
@@ -3191,10 +3200,7 @@ You are a helpful product assistant. Use the provided context to answer question
3191
3200
  metadata: chunk.metadata
3192
3201
  }));
3193
3202
  const totalProcessed = await this.processUpserts(upsertDocs, ns);
3194
- results.push({
3195
- docId: doc.docId,
3196
- chunksIngested: totalProcessed
3197
- });
3203
+ results.push({ docId: doc.docId, chunksIngested: totalProcessed });
3198
3204
  if (this.graphDB && this.entityExtractor) {
3199
3205
  await this.processGraphIngestion(doc.docId, chunks);
3200
3206
  }
@@ -3205,23 +3211,18 @@ You are a helpful product assistant. Use the provided context to answer question
3205
3211
  }
3206
3212
  return results;
3207
3213
  }
3208
- /**
3209
- * Step 1: Chunk the document content.
3210
- */
3214
+ /** Step 1: Chunk the document content. */
3211
3215
  async prepareChunks(doc) {
3212
3216
  var _a, _b;
3213
3217
  if (this.llamaIngestor) {
3214
- return await this.llamaIngestor.chunk(doc.content, {
3218
+ return this.llamaIngestor.chunk(doc.content, {
3215
3219
  docId: doc.docId,
3216
3220
  metadata: doc.metadata,
3217
3221
  chunkSize: (_a = this.config.rag) == null ? void 0 : _a.chunkSize,
3218
3222
  chunkOverlap: (_b = this.config.rag) == null ? void 0 : _b.chunkOverlap
3219
3223
  });
3220
3224
  }
3221
- return this.chunker.chunk(doc.content, {
3222
- docId: doc.docId,
3223
- metadata: doc.metadata
3224
- });
3225
+ return this.chunker.chunk(doc.content, { docId: doc.docId, metadata: doc.metadata });
3225
3226
  }
3226
3227
  /**
3227
3228
  * Step 2: Generate embeddings for chunks with retry logic.
@@ -3245,9 +3246,7 @@ You are a helpful product assistant. Use the provided context to answer question
3245
3246
  }
3246
3247
  return vectors;
3247
3248
  }
3248
- /**
3249
- * Step 3: Upsert chunks to vector database with retry logic.
3250
- */
3249
+ /** Step 3: Upsert chunks to vector database with retry logic. */
3251
3250
  async processUpserts(upsertDocs, namespace) {
3252
3251
  const upsertBatchOptions = {
3253
3252
  batchSize: 100,
@@ -3264,14 +3263,10 @@ You are a helpful product assistant. Use the provided context to answer question
3264
3263
  }
3265
3264
  return upsertResult.totalProcessed;
3266
3265
  }
3267
- /**
3268
- * Step 4: Optional graph-based entity extraction and ingestion.
3269
- */
3266
+ /** Step 4: Optional graph-based entity extraction and ingestion. */
3270
3267
  async processGraphIngestion(docId, chunks) {
3271
- console.log(`[Pipeline] Extracting entities for doc ${docId} (${chunks.length} chunks)...`);
3272
3268
  const extractionOptions = {
3273
3269
  batchSize: 2,
3274
- // Low concurrency for LLM extraction
3275
3270
  maxRetries: 1,
3276
3271
  initialDelayMs: 500
3277
3272
  };
@@ -3284,7 +3279,7 @@ You are a helpful product assistant. Use the provided context to answer question
3284
3279
  if (nodes.length > 0) await this.graphDB.addNodes(nodes);
3285
3280
  if (edges.length > 0) await this.graphDB.addEdges(edges);
3286
3281
  } catch (err) {
3287
- console.warn(`[Pipeline] Entity extraction failed for chunk:`, err);
3282
+ console.warn(`[Pipeline] Entity extraction failed for chunk in doc ${docId}:`, err);
3288
3283
  }
3289
3284
  }
3290
3285
  },
@@ -3295,7 +3290,6 @@ You are a helpful product assistant. Use the provided context to answer question
3295
3290
  var _a;
3296
3291
  await this.initialize();
3297
3292
  if (((_a = this.config.rag) == null ? void 0 : _a.architecture) === "agentic" && this.agent) {
3298
- console.log("[Pipeline] \u{1F916} Executing in Agentic Mode...");
3299
3293
  const agentReply = await this.agent.run(question, history);
3300
3294
  return { reply: agentReply, sources: [] };
3301
3295
  }
@@ -3304,6 +3298,7 @@ You are a helpful product assistant. Use the provided context to answer question
3304
3298
  let sources = [];
3305
3299
  let graphData;
3306
3300
  let uiTransformation;
3301
+ let trace;
3307
3302
  try {
3308
3303
  for (var iter = __forAwait(stream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
3309
3304
  const chunk = temp.value;
@@ -3313,6 +3308,7 @@ You are a helpful product assistant. Use the provided context to answer question
3313
3308
  if ("sources" in chunk) sources = chunk.sources;
3314
3309
  if ("graphData" in chunk) graphData = chunk.graphData;
3315
3310
  if ("ui_transformation" in chunk) uiTransformation = chunk.ui_transformation;
3311
+ if ("trace" in chunk) trace = chunk.trace;
3316
3312
  }
3317
3313
  }
3318
3314
  } catch (temp) {
@@ -3325,38 +3321,47 @@ You are a helpful product assistant. Use the provided context to answer question
3325
3321
  throw error[0];
3326
3322
  }
3327
3323
  }
3328
- return { reply, sources, graphData, ui_transformation: uiTransformation };
3324
+ return { reply, sources, graphData, ui_transformation: uiTransformation, trace };
3329
3325
  }
3330
3326
  /**
3331
3327
  * High-performance streaming RAG flow.
3332
- * Yields text chunks first, then the retrieval metadata at the end.
3328
+ * Yields text chunks first, then the retrieval metadata + observability trace at the end.
3333
3329
  */
3334
3330
  askStream(_0) {
3335
3331
  return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
3336
- var _a, _b, _c, _d, _e, _f, _g;
3332
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
3337
3333
  yield new __await(this.initialize());
3338
3334
  const ns = namespace != null ? namespace : this.config.projectId;
3339
3335
  const topK = (_b = (_a = this.config.rag) == null ? void 0 : _a.topK) != null ? _b : 5;
3340
3336
  const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0;
3337
+ const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
3338
+ const requestStart = performance.now();
3341
3339
  try {
3342
3340
  let searchQuery = question;
3341
+ let rewrittenQuery;
3343
3342
  if ((_e = this.config.rag) == null ? void 0 : _e.useQueryTransformation) {
3344
3343
  searchQuery = yield new __await(this.rewriteQuery(question, history));
3344
+ rewrittenQuery = searchQuery !== question ? searchQuery : void 0;
3345
3345
  }
3346
3346
  const hints = QueryProcessor.extractQueryFieldHints(question, (_f = this.config.rag) == null ? void 0 : _f.filterableFields);
3347
3347
  const filter = QueryProcessor.buildQueryFilter(question, hints);
3348
- console.log(`[Pipeline] \u{1F9E9} Extracted filters:`, JSON.stringify(filter));
3348
+ const embedStart = performance.now();
3349
3349
  const { sources: rawSources, graphData } = yield new __await(this.retrieve(searchQuery, {
3350
3350
  namespace: ns,
3351
3351
  topK: topK * 2,
3352
3352
  filter
3353
3353
  }));
3354
+ const retrieveEnd = performance.now();
3355
+ const embedMs = retrieveEnd - embedStart;
3356
+ const retrieveMs = retrieveEnd - embedStart;
3357
+ const rerankStart = performance.now();
3354
3358
  let sources = rawSources.filter((m) => m.score >= scoreThreshold);
3355
3359
  if ((_g = this.config.rag) == null ? void 0 : _g.useReranking) {
3356
3360
  sources = yield new __await(this.reranker.rerank(sources, question, topK));
3357
3361
  } else {
3358
3362
  sources = sources.slice(0, topK);
3359
3363
  }
3364
+ const rerankMs = performance.now() - rerankStart;
3360
3365
  let context = sources.length ? sources.map((m, i) => `[Source ${i + 1}]
3361
3366
  ${m.content}`).join("\n\n---\n\n") : "No relevant context found.";
3362
3367
  if (graphData && graphData.nodes.length > 0) {
@@ -3375,6 +3380,10 @@ ${context}`;
3375
3380
  const hardenedHistory = [...history];
3376
3381
  const userQuestion = { role: "user", content: question + restrictionSuffix };
3377
3382
  const messages = [...hardenedHistory, userQuestion];
3383
+ const systemPrompt = (_h = this.config.llm.systemPrompt) != null ? _h : "";
3384
+ const userPrompt = messages.map((m) => `${m.role}: ${m.content}`).join("\n");
3385
+ let fullReply = "";
3386
+ const generateStart = performance.now();
3378
3387
  if (this.llmProvider.chatStream) {
3379
3388
  const stream = this.llmProvider.chatStream(messages, context);
3380
3389
  if (!stream) {
@@ -3383,6 +3392,7 @@ ${context}`;
3383
3392
  try {
3384
3393
  for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
3385
3394
  const chunk = temp.value;
3395
+ fullReply += chunk;
3386
3396
  yield chunk;
3387
3397
  }
3388
3398
  } catch (temp) {
@@ -3397,15 +3407,58 @@ ${context}`;
3397
3407
  }
3398
3408
  } else {
3399
3409
  const reply = yield new __await(this.llmProvider.chat(messages, context));
3410
+ fullReply = reply;
3400
3411
  yield reply;
3401
3412
  }
3413
+ const generateMs = performance.now() - generateStart;
3414
+ const totalMs = performance.now() - requestStart;
3415
+ const latency = {
3416
+ embedMs: Math.round(embedMs),
3417
+ retrieveMs: Math.round(retrieveMs),
3418
+ rerankMs: ((_i = this.config.rag) == null ? void 0 : _i.useReranking) ? Math.round(rerankMs) : void 0,
3419
+ generateMs: Math.round(generateMs),
3420
+ totalMs: Math.round(totalMs)
3421
+ };
3422
+ const promptText = systemPrompt + "\n" + context + "\n" + userPrompt;
3423
+ const promptTokens = estimateTokens(promptText);
3424
+ const completionTokens = estimateTokens(fullReply);
3425
+ const tokens = {
3426
+ promptTokens,
3427
+ completionTokens,
3428
+ totalTokens: promptTokens + completionTokens,
3429
+ estimatedCostUsd: estimateCostUsd(promptTokens, completionTokens, this.config.llm.model)
3430
+ };
3431
+ const hallucinationResult = yield new __await(scoreHallucination(this.llmProvider, fullReply, context).catch(() => void 0));
3402
3432
  const trainedSchema = yield new __await(trainingPromise);
3403
3433
  const uiTransformation = yield new __await(this.generateUiTransformation(question, sources, context, trainedSchema));
3434
+ const trace = {
3435
+ requestId,
3436
+ query: question,
3437
+ rewrittenQuery,
3438
+ systemPrompt,
3439
+ userPrompt: question + restrictionSuffix,
3440
+ chunks: sources.map((s) => {
3441
+ var _a2;
3442
+ return {
3443
+ id: s.id,
3444
+ score: s.score,
3445
+ content: s.content,
3446
+ metadata: (_a2 = s.metadata) != null ? _a2 : {},
3447
+ namespace: ns
3448
+ };
3449
+ }),
3450
+ latency,
3451
+ tokens,
3452
+ hallucinationScore: hallucinationResult == null ? void 0 : hallucinationResult.score,
3453
+ hallucinationReason: hallucinationResult == null ? void 0 : hallucinationResult.reason,
3454
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
3455
+ };
3404
3456
  yield {
3405
3457
  reply: "",
3406
3458
  sources,
3407
3459
  graphData,
3408
- ui_transformation: uiTransformation
3460
+ ui_transformation: uiTransformation,
3461
+ trace
3409
3462
  };
3410
3463
  } catch (error2) {
3411
3464
  throw new Error(`[Pipeline] Stream failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
@@ -3444,12 +3497,9 @@ ${context}`;
3444
3497
  const sources = await this.vectorDB.query(queryVector, topK, ns, options.filter);
3445
3498
  return { sources, graphData };
3446
3499
  }
3447
- /**
3448
- * Rewrite the user query for better retrieval performance.
3449
- */
3500
+ /** Rewrite the user query for better retrieval performance. */
3450
3501
  async rewriteQuery(question, history) {
3451
- const prompt = `
3452
- Given the following conversation history and a new question, rewrite the question to be a better search query for a vector database.
3502
+ const prompt = `Given the following conversation history and a new question, rewrite the question to be a better search query for a vector database.
3453
3503
  Focus on extracting the core intent and entities. Do not answer the question, just rewrite it.
3454
3504
 
3455
3505
  History:
@@ -3467,23 +3517,16 @@ Optimized Search Query:`;
3467
3517
  );
3468
3518
  return rewrite.trim() || question;
3469
3519
  }
3470
- /**
3471
- * Generate 3-5 short, relevant questions based on the vector database content.
3472
- */
3520
+ /** Generate 3-5 short, relevant questions based on the vector database content. */
3473
3521
  async getSuggestions(query, namespace) {
3474
- if (!query || query.trim().length < 3) {
3475
- return [];
3476
- }
3522
+ if (!query || query.trim().length < 3) return [];
3477
3523
  await this.initialize();
3478
3524
  const ns = namespace != null ? namespace : this.config.projectId;
3479
3525
  try {
3480
3526
  const { sources } = await this.retrieve(query, { namespace: ns, topK: 3 });
3481
- if (sources.length === 0) {
3482
- return [];
3483
- }
3527
+ if (sources.length === 0) return [];
3484
3528
  const context = sources.map((s) => s.content).join("\n\n---\n\n");
3485
- const prompt = `
3486
- Based on the following snippets from a document, what are 3 short, relevant questions a user might ask?
3529
+ const prompt = `Based on the following snippets from a document, what are 3 short, relevant questions a user might ask?
3487
3530
  Focus on questions that can be answered by the context.
3488
3531
  Keep each question under 10 words and make them very specific to the content.
3489
3532
  Return ONLY a JSON array of strings like ["Question 1", "Question 2", "Question 3"].
@@ -3760,6 +3803,11 @@ function sseMetaFrame(meta) {
3760
3803
  function sseUIFrame(uiTransformation) {
3761
3804
  return `data: ${JSON.stringify({ type: "ui_transformation", data: uiTransformation })}
3762
3805
 
3806
+ `;
3807
+ }
3808
+ function sseObservabilityFrame(trace) {
3809
+ return `data: ${JSON.stringify({ type: "observability", data: trace })}
3810
+
3763
3811
  `;
3764
3812
  }
3765
3813
  function sseErrorFrame(message) {
@@ -3826,6 +3874,9 @@ function createStreamHandler(configOrPlugin) {
3826
3874
  enqueue(sseMetaFrame(chunk));
3827
3875
  const responseChunk = chunk;
3828
3876
  const sources = (responseChunk == null ? void 0 : responseChunk.sources) || [];
3877
+ if (responseChunk == null ? void 0 : responseChunk.trace) {
3878
+ enqueue(sseObservabilityFrame(responseChunk.trace));
3879
+ }
3829
3880
  if (sources.length > 0) {
3830
3881
  try {
3831
3882
  const llmProvider = (_a = plugin.getLLMProvider) == null ? void 0 : _a.call(plugin);
@@ -3907,24 +3958,64 @@ function createUploadHandler(configOrPlugin) {
3907
3958
  const formData = await req.formData();
3908
3959
  const files = formData.getAll("files");
3909
3960
  const namespace = formData.get("namespace") || void 0;
3961
+ const dimensionRaw = formData.get("dimension");
3962
+ const dimension = dimensionRaw ? parseInt(dimensionRaw, 10) : void 0;
3910
3963
  if (!files || files.length === 0) {
3911
3964
  return NextResponse.json({ error: "No files provided" }, { status: 400 });
3912
3965
  }
3913
- const documents = await Promise.all(
3914
- files.map(async (file) => {
3966
+ const documents = [];
3967
+ for (const file of files) {
3968
+ if (file.name.toLowerCase().endsWith(".csv") || file.type === "text/csv") {
3969
+ const text = await file.text();
3970
+ const Papa = await import("papaparse");
3971
+ const parsed = Papa.default.parse(text, { header: true, skipEmptyLines: true });
3972
+ if (parsed.data && parsed.data.length > 0) {
3973
+ let i = 0;
3974
+ let lastRowData = null;
3975
+ for (const row of parsed.data) {
3976
+ i++;
3977
+ const rowData = row;
3978
+ const groupingKey = Object.keys(rowData)[0];
3979
+ if (lastRowData && groupingKey && rowData[groupingKey] && rowData[groupingKey] === lastRowData[groupingKey]) {
3980
+ for (const key of Object.keys(rowData)) {
3981
+ if (!rowData[key] && lastRowData[key]) {
3982
+ rowData[key] = lastRowData[key];
3983
+ }
3984
+ }
3985
+ }
3986
+ lastRowData = __spreadValues({}, rowData);
3987
+ const contentParts = [];
3988
+ for (const [key, val] of Object.entries(rowData)) {
3989
+ if (key && val) {
3990
+ contentParts.push(`${key}: ${val}`);
3991
+ }
3992
+ }
3993
+ documents.push({
3994
+ docId: `${file.name}-row-${i}`,
3995
+ content: contentParts.join(", "),
3996
+ metadata: __spreadValues(__spreadValues({
3997
+ fileName: file.name,
3998
+ fileSize: file.size,
3999
+ fileType: file.type,
4000
+ uploadedAt: (/* @__PURE__ */ new Date()).toISOString()
4001
+ }, dimension ? { dimension } : {}), rowData)
4002
+ });
4003
+ }
4004
+ }
4005
+ } else {
3915
4006
  const content = await DocumentParser.parse(file, file.name, file.type);
3916
- return {
4007
+ documents.push({
3917
4008
  docId: file.name,
3918
4009
  content,
3919
- metadata: {
4010
+ metadata: __spreadValues({
3920
4011
  fileName: file.name,
3921
4012
  fileSize: file.size,
3922
4013
  fileType: file.type,
3923
4014
  uploadedAt: (/* @__PURE__ */ new Date()).toISOString()
3924
- }
3925
- };
3926
- })
3927
- );
4015
+ }, dimension ? { dimension } : {})
4016
+ });
4017
+ }
4018
+ }
3928
4019
  const results = await plugin.ingest(documents, namespace);
3929
4020
  return NextResponse.json({ message: "Upload successful", results });
3930
4021
  } catch (err) {
@@ -3975,6 +4066,7 @@ export {
3975
4066
  sseTextFrame,
3976
4067
  sseMetaFrame,
3977
4068
  sseUIFrame,
4069
+ sseObservabilityFrame,
3978
4070
  sseErrorFrame,
3979
4071
  createChatHandler,
3980
4072
  createStreamHandler,