@retrivora-ai/rag-engine 1.9.8 → 1.9.9

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 (37) hide show
  1. package/README.md +36 -28
  2. package/dist/{ILLMProvider-B8ROITYK.d.mts → ILLMProvider-DMxLyTdq.d.mts} +2 -2
  3. package/dist/{ILLMProvider-B8ROITYK.d.ts → ILLMProvider-DMxLyTdq.d.ts} +2 -2
  4. package/dist/handlers/index.d.mts +2 -2
  5. package/dist/handlers/index.d.ts +2 -2
  6. package/dist/handlers/index.js +140 -28
  7. package/dist/handlers/index.mjs +146 -28
  8. package/dist/{index-DNvoi-sV.d.ts → index-CfkqZd2Y.d.ts} +1 -1
  9. package/dist/{index-CrxCy36A.d.mts → index-DXd29KMq.d.mts} +1 -1
  10. package/dist/{index-BCPKUAVL.d.ts → index-D_bOdJML.d.ts} +1 -1
  11. package/dist/{index-B8PbEFSY.d.mts → index-xygonxpW.d.mts} +1 -1
  12. package/dist/index.css +485 -557
  13. package/dist/index.d.mts +16 -10
  14. package/dist/index.d.ts +16 -10
  15. package/dist/index.js +24 -765
  16. package/dist/index.mjs +20 -779
  17. package/dist/server.d.mts +8 -5
  18. package/dist/server.d.ts +8 -5
  19. package/dist/server.js +141 -28
  20. package/dist/server.mjs +147 -28
  21. package/package.json +3 -2
  22. package/src/app/page.tsx +2 -0
  23. package/src/components/constants.tsx +224 -0
  24. package/src/config/RagConfig.ts +2 -2
  25. package/src/core/ConfigResolver.ts +32 -6
  26. package/src/core/LicenseVerifier.ts +106 -0
  27. package/src/core/Pipeline.ts +8 -6
  28. package/src/core/Retrivora.ts +1 -0
  29. package/src/index.ts +3 -5
  30. package/src/components/AmbientBackground.tsx +0 -29
  31. package/src/components/ArchitectureCard.tsx +0 -53
  32. package/src/components/ArchitectureCardsSection.tsx +0 -48
  33. package/src/components/DocViewer.tsx +0 -97
  34. package/src/components/Documentation.tsx +0 -141
  35. package/src/components/Hero.tsx +0 -142
  36. package/src/components/Lifecycle.tsx +0 -77
  37. package/src/components/Navbar.tsx +0 -55
package/dist/server.mjs CHANGED
@@ -19,6 +19,12 @@ var __spreadValues = (a, b) => {
19
19
  return a;
20
20
  };
21
21
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
22
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
23
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
24
+ }) : x)(function(x) {
25
+ if (typeof require !== "undefined") return require.apply(this, arguments);
26
+ throw Error('Dynamic require of "' + x + '" is not supported');
27
+ });
22
28
  var __objRest = (source, exclude) => {
23
29
  var target = {};
24
30
  for (var prop in source)
@@ -2344,7 +2350,7 @@ var ConfigResolver = class {
2344
2350
  }
2345
2351
  }
2346
2352
  static mergeRetrievalWorkflow(rag, retrieval, workflow) {
2347
- var _a2, _b, _c, _d, _e;
2353
+ var _a2, _b, _c, _d, _e, _f;
2348
2354
  if (!rag && !retrieval && !workflow) return void 0;
2349
2355
  const normalized = __spreadValues({}, rag != null ? rag : {});
2350
2356
  if (retrieval) {
@@ -2352,20 +2358,44 @@ var ConfigResolver = class {
2352
2358
  normalized.scoreThreshold = (_b = retrieval.scoreThreshold) != null ? _b : normalized.scoreThreshold;
2353
2359
  normalized.useReranking = (_c = retrieval.useReranking) != null ? _c : normalized.useReranking;
2354
2360
  if (retrieval.strategy === "hybrid") normalized.architecture = (_d = normalized.architecture) != null ? _d : "hybrid";
2355
- if (retrieval.strategy === "agentic") normalized.architecture = "agentic";
2356
- if (retrieval.strategy === "contextual-compression") normalized.useReranking = true;
2361
+ if (retrieval.strategy === "agentic") normalized.architecture = "multi-agent";
2362
+ if (retrieval.strategy === "contextual-compression") {
2363
+ normalized.useReranking = true;
2364
+ normalized.architecture = (_e = normalized.architecture) != null ? _e : "retrieve-and-rerank";
2365
+ }
2357
2366
  }
2358
2367
  if (workflow == null ? void 0 : workflow.type) {
2359
2368
  const type = workflow.type;
2360
- if (type === "agentic" || type === "agentic-rag") normalized.architecture = "agentic";
2361
- else if (type === "hybrid-rag") normalized.architecture = "hybrid";
2362
- else if (type === "graph-rag") {
2369
+ if (type === "naive-rag") {
2370
+ normalized.architecture = "naive";
2371
+ normalized.useReranking = false;
2372
+ normalized.useGraphRetrieval = false;
2373
+ } else if (type === "retrieve-and-rerank") {
2374
+ normalized.architecture = "retrieve-and-rerank";
2375
+ normalized.useReranking = true;
2376
+ } else if (type === "multimodal-rag") {
2377
+ normalized.architecture = "multimodal";
2378
+ } else if (type === "graph-rag") {
2363
2379
  normalized.architecture = "graph";
2364
2380
  normalized.useGraphRetrieval = true;
2381
+ } else if (type === "hybrid-rag") {
2382
+ normalized.architecture = "hybrid";
2383
+ } else if (type === "agentic-router") {
2384
+ normalized.architecture = "agentic-router";
2385
+ } else if (type === "multi-agent-rag" || type === "multi-agent" || type === "agentic" || type === "agentic-rag") {
2386
+ normalized.architecture = "multi-agent";
2365
2387
  } else if (type === "simple-rag" || type === "rag") {
2366
- normalized.architecture = (_e = normalized.architecture) != null ? _e : "simple";
2388
+ normalized.architecture = (_f = normalized.architecture) != null ? _f : "naive";
2367
2389
  }
2368
2390
  }
2391
+ if (normalized.architecture === "retrieve-and-rerank") {
2392
+ normalized.useReranking = true;
2393
+ } else if (normalized.architecture === "graph") {
2394
+ normalized.useGraphRetrieval = true;
2395
+ } else if (normalized.architecture === "naive") {
2396
+ normalized.useReranking = false;
2397
+ normalized.useGraphRetrieval = false;
2398
+ }
2369
2399
  return normalized;
2370
2400
  }
2371
2401
  };
@@ -4220,6 +4250,19 @@ var LicenseVerifier = class {
4220
4250
  */
4221
4251
  static verify(licenseKey, currentProjectId, provider, publicKeyOverride) {
4222
4252
  const isProduction = process.env.NODE_ENV === "production";
4253
+ const now = Date.now();
4254
+ if (licenseKey) {
4255
+ const cacheKey = `${licenseKey}:${currentProjectId}:${provider || ""}:${publicKeyOverride || ""}`;
4256
+ const cached = this.cache.get(cacheKey);
4257
+ if (cached && now - cached.cachedAt < this.CACHE_TTL_MS) {
4258
+ const currentTimestampSec = Math.floor(now / 1e3);
4259
+ if (cached.payload.expiresAt && currentTimestampSec > cached.payload.expiresAt) {
4260
+ this.cache.delete(cacheKey);
4261
+ } else {
4262
+ return cached.payload;
4263
+ }
4264
+ }
4265
+ }
4223
4266
  if (!licenseKey) {
4224
4267
  if (isProduction) {
4225
4268
  throw new ConfigurationException(
@@ -4306,6 +4349,10 @@ var LicenseVerifier = class {
4306
4349
  }
4307
4350
  }
4308
4351
  }
4352
+ if (licenseKey) {
4353
+ const cacheKey = `${licenseKey}:${currentProjectId}:${provider || ""}:${publicKeyOverride || ""}`;
4354
+ this.cache.set(cacheKey, { payload, cachedAt: now });
4355
+ }
4309
4356
  return payload;
4310
4357
  } catch (err) {
4311
4358
  const message = err instanceof Error ? err.message : String(err);
@@ -4314,7 +4361,76 @@ var LicenseVerifier = class {
4314
4361
  );
4315
4362
  }
4316
4363
  }
4364
+ static async verifyIP(licenseKey) {
4365
+ if (!licenseKey) return;
4366
+ try {
4367
+ const parts = licenseKey.split(".");
4368
+ if (parts.length !== 3) return;
4369
+ const [, payloadB64] = parts;
4370
+ const payload = JSON.parse(
4371
+ Buffer.from(payloadB64, "base64url").toString("utf8")
4372
+ );
4373
+ const tier = (payload.tier || "").toLowerCase();
4374
+ if (tier === "enterprise" || tier === "custom") {
4375
+ return;
4376
+ }
4377
+ if (payload.ipv4 || payload.ipv6) {
4378
+ let currentIpv4 = "";
4379
+ let currentIpv6 = "";
4380
+ try {
4381
+ const res = await fetch("https://api4.ipify.org?format=json", { signal: AbortSignal.timeout(3e3) });
4382
+ const data = await res.json();
4383
+ currentIpv4 = data.ip;
4384
+ } catch (e) {
4385
+ }
4386
+ try {
4387
+ const res = await fetch("https://api6.ipify.org?format=json", { signal: AbortSignal.timeout(3e3) });
4388
+ const data = await res.json();
4389
+ currentIpv6 = data.ip;
4390
+ } catch (e) {
4391
+ }
4392
+ const localIps = [];
4393
+ try {
4394
+ const osModule = __require("os");
4395
+ const interfaces = osModule.networkInterfaces();
4396
+ for (const name of Object.keys(interfaces)) {
4397
+ for (const iface of interfaces[name] || []) {
4398
+ if (!iface.internal) {
4399
+ localIps.push(iface.address);
4400
+ }
4401
+ }
4402
+ }
4403
+ } catch (e) {
4404
+ }
4405
+ const isIpv4Match = payload.ipv4 && (currentIpv4 === payload.ipv4 || localIps.includes(payload.ipv4));
4406
+ const isIpv6Match = payload.ipv6 && (currentIpv6 === payload.ipv6 || localIps.includes(payload.ipv6));
4407
+ if (payload.ipv4 && payload.ipv6) {
4408
+ if (!isIpv4Match && !isIpv6Match) {
4409
+ throw new Error(
4410
+ `License key access restricted. This license key was created for a different system (authorized IPv4: ${payload.ipv4}, IPv6: ${payload.ipv6}) and cannot be used on this machine.`
4411
+ );
4412
+ }
4413
+ } else if (payload.ipv4 && !isIpv4Match) {
4414
+ throw new Error(
4415
+ `License key access restricted. This license key was created for a different system (authorized IPv4: ${payload.ipv4}) and cannot be used on this machine.`
4416
+ );
4417
+ } else if (payload.ipv6 && !isIpv6Match) {
4418
+ throw new Error(
4419
+ `License key access restricted. This license key was created for a different system (authorized IPv6: ${payload.ipv6}) and cannot be used on this machine.`
4420
+ );
4421
+ }
4422
+ }
4423
+ } catch (err) {
4424
+ if (err.message.includes("License key access restricted")) {
4425
+ throw new ConfigurationException(`[Retrivora SDK] ${err.message}`);
4426
+ }
4427
+ }
4428
+ }
4317
4429
  };
4430
+ // A simple in-memory cache to save CPU overhead of cryptographic signature checks.
4431
+ LicenseVerifier.cache = /* @__PURE__ */ new Map();
4432
+ LicenseVerifier.CACHE_TTL_MS = 60 * 1e3;
4433
+ // Cache verified license for 60 seconds
4318
4434
  // Retrivora's Public Key used to verify the license key signature.
4319
4435
  // In production, this matches the private key held by Retrivora SaaS.
4320
4436
  LicenseVerifier.PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
@@ -7275,7 +7391,7 @@ var Pipeline = class {
7275
7391
  return this.initialised ? this.llmProvider : void 0;
7276
7392
  }
7277
7393
  async initialize() {
7278
- var _a2, _b, _c;
7394
+ var _a2, _b, _c, _d;
7279
7395
  if (this.initialised) return;
7280
7396
  const chartInstruction = `You are a helpful assistant. Use the provided context to answer questions accurately.
7281
7397
 
@@ -7318,7 +7434,7 @@ var Pipeline = class {
7318
7434
  this.entityExtractor = new EntityExtractor(this.llmProvider);
7319
7435
  }
7320
7436
  await this.vectorDB.initialize();
7321
- if (((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || this.config.mcpServers && this.config.mcpServers.length > 0) {
7437
+ if (((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || ((_b = this.config.rag) == null ? void 0 : _b.architecture) === "multi-agent" || this.config.mcpServers && this.config.mcpServers.length > 0) {
7322
7438
  this.mcpRegistry = new MCPRegistry(this.config.mcpServers || []);
7323
7439
  this.multiAgentCoordinator = new MultiAgentCoordinator({
7324
7440
  llmProvider: this.llmProvider,
@@ -7330,7 +7446,7 @@ var Pipeline = class {
7330
7446
  this.agent = new LangChainAgent(this, this.config);
7331
7447
  await this.agent.initialize(this.llmProvider);
7332
7448
  }
7333
- if ((_c = (_b = this.config.rag) == null ? void 0 : _b.cag) == null ? void 0 : _c.enabled) {
7449
+ if ((_d = (_c = this.config.rag) == null ? void 0 : _c.cag) == null ? void 0 : _d.enabled) {
7334
7450
  await this.loadColdContext(this.config.projectId);
7335
7451
  }
7336
7452
  this.initialised = true;
@@ -7493,9 +7609,9 @@ ${m.content}`).join("\n\n---\n\n");
7493
7609
  return { reply, sources };
7494
7610
  }
7495
7611
  async ask(question, history = [], namespace) {
7496
- var _a2;
7612
+ var _a2, _b;
7497
7613
  await this.initialize();
7498
- if ((((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || this.config.mcpServers && this.config.mcpServers.length > 0) && this.multiAgentCoordinator) {
7614
+ if ((((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || ((_b = this.config.rag) == null ? void 0 : _b.architecture) === "multi-agent" || this.config.mcpServers && this.config.mcpServers.length > 0) && this.multiAgentCoordinator) {
7499
7615
  return await this.multiAgentCoordinator.run(question, history);
7500
7616
  }
7501
7617
  const stream = this.askStream(question, history, namespace);
@@ -7530,9 +7646,9 @@ ${m.content}`).join("\n\n---\n\n");
7530
7646
  }
7531
7647
  askStream(_0) {
7532
7648
  return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
7533
- var _a2;
7649
+ var _a2, _b;
7534
7650
  yield new __await(this.initialize());
7535
- if ((((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || this.config.mcpServers && this.config.mcpServers.length > 0) && this.multiAgentCoordinator) {
7651
+ if ((((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || ((_b = this.config.rag) == null ? void 0 : _b.architecture) === "multi-agent" || this.config.mcpServers && this.config.mcpServers.length > 0) && this.multiAgentCoordinator) {
7536
7652
  const stream2 = this.multiAgentCoordinator.runStream(question, history);
7537
7653
  try {
7538
7654
  for (var iter = __forAwait(stream2), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
@@ -7581,7 +7697,7 @@ ${m.content}`).join("\n\n---\n\n");
7581
7697
  */
7582
7698
  askStreamInternal(_0) {
7583
7699
  return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
7584
- var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
7700
+ var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A;
7585
7701
  yield new __await(this.initialize());
7586
7702
  const ns = namespace != null ? namespace : this.config.projectId;
7587
7703
  const topK = (_b = (_a2 = this.config.rag) == null ? void 0 : _a2.topK) != null ? _b : 5;
@@ -7604,13 +7720,14 @@ ${m.content}`).join("\n\n---\n\n");
7604
7720
  const embedStart = performance.now();
7605
7721
  const cacheKey = `${ns}::${searchQuery}`;
7606
7722
  const cachedVector = this.embeddingCache.get(cacheKey);
7607
- const useGraph = this.graphDB && ((_h = this.config.rag) == null ? void 0 : _h.useGraphRetrieval);
7723
+ const arch = (_h = this.config.rag) == null ? void 0 : _h.architecture;
7724
+ const useGraph = arch !== "naive" && arch !== "retrieve-and-rerank" && this.graphDB && ((_i = this.config.rag) == null ? void 0 : _i.useGraphRetrieval);
7608
7725
  const [strategyResult, embeddedVector] = yield new __await(Promise.all([
7609
7726
  QueryProcessor.determineRetrievalStrategy(
7610
7727
  searchQuery,
7611
7728
  useGraph ? this.llmRouter.get("fast") : void 0,
7612
- (_i = this.config.rag) == null ? void 0 : _i.graphKeywords,
7613
- (_j = this.config.rag) == null ? void 0 : _j.vectorKeywords
7729
+ (_j = this.config.rag) == null ? void 0 : _j.graphKeywords,
7730
+ (_k = this.config.rag) == null ? void 0 : _k.vectorKeywords
7614
7731
  ),
7615
7732
  // Embed immediately regardless of strategy — costs nothing if cached.
7616
7733
  // If strategy turns out to be 'graph'-only we just won't use the vector.
@@ -7620,7 +7737,7 @@ ${m.content}`).join("\n\n---\n\n");
7620
7737
  if (!cachedVector && queryVector.length > 0) {
7621
7738
  this.embeddingCache.set(cacheKey, queryVector);
7622
7739
  }
7623
- const graphData = (strategyResult === "graph" || strategyResult === "both") && this.graphDB && ((_k = this.config.rag) == null ? void 0 : _k.useGraphRetrieval) ? yield new __await(this.graphDB.query(searchQuery)) : void 0;
7740
+ const graphData = (strategyResult === "graph" || strategyResult === "both") && this.graphDB && ((_l = this.config.rag) == null ? void 0 : _l.useGraphRetrieval) ? yield new __await(this.graphDB.query(searchQuery)) : void 0;
7624
7741
  const hasMetadataFilter = filter.metadata && Object.keys(filter.metadata).length > 0;
7625
7742
  const hasNumericPredicates = Array.isArray(filter.__numericPredicates) && filter.__numericPredicates.length > 0;
7626
7743
  const wantsExhaustiveList = hasNumericPredicates || hasMetadataFilter || /\b(list|all|show|provide|give|get|browse|find|search|display)\b/i.test(question);
@@ -7633,7 +7750,8 @@ ${m.content}`).join("\n\n---\n\n");
7633
7750
  const structuredSources = this.applyStructuredFilters(rawSources, filter);
7634
7751
  let fullSources = hasNumericPredicates ? structuredSources : structuredSources.filter((m) => m.score >= scoreThreshold);
7635
7752
  const rerankLimit = wantsExhaustiveList ? retrievalLimit : topK;
7636
- if (!hasNumericPredicates && ((_l = this.config.rag) == null ? void 0 : _l.useReranking)) {
7753
+ const useReranking = arch !== "naive" && (arch === "retrieve-and-rerank" || ((_m = this.config.rag) == null ? void 0 : _m.useReranking));
7754
+ if (!hasNumericPredicates && useReranking) {
7637
7755
  fullSources = yield new __await(this.reranker.rerank(fullSources, question, rerankLimit));
7638
7756
  } else if (!wantsExhaustiveList) {
7639
7757
  fullSources = fullSources.slice(0, topK);
@@ -7663,7 +7781,7 @@ ${graphContext}
7663
7781
  VECTOR CONTEXT:
7664
7782
  ${context}`;
7665
7783
  }
7666
- if ((_n = (_m = this.config.rag) == null ? void 0 : _m.cag) == null ? void 0 : _n.enabled) {
7784
+ if ((_o = (_n = this.config.rag) == null ? void 0 : _n.cag) == null ? void 0 : _o.enabled) {
7667
7785
  if (!this.coldContexts.has(ns)) {
7668
7786
  yield new __await(this.loadColdContext(ns));
7669
7787
  }
@@ -7716,10 +7834,10 @@ ${context}`;
7716
7834
  let hallucinationScoringPromise = Promise.resolve(void 0);
7717
7835
  const restrictionSuffix = "\n\n(IMPORTANT: Format your response beautifully using rich Markdown! Use bolding for emphasis, headings (##) for structure, bullet points for lists, and proper line breaks between paragraphs to make it highly readable. However, NEVER generate Markdown tables, HTML figures, or text charts (the UI renders requested charts separately, so NEVER say you cannot create, display, draw, render, or provide a chart/visualization). If listing products, use simple markdown bullet points or comma-separated names. NEVER use plus signs (+) to separate product names, category names, or list items. For product description/detail questions, provide customer-facing prose only and do NOT list internal catalog fields such as Handle, Body (HTML), Vendor, Type, Tags, Published, Option, Variant, SKU, or raw metadata labels. You CAN use numbers for years/counts like 2006 or 5800, but NEVER put a dollar sign ($) before them.)";
7718
7836
  const isClaude37 = this.config.llm.model.includes("claude-3-7-sonnet");
7719
- const isNativeThinking = isClaude37 && (((_o = this.config.llm.options) == null ? void 0 : _o.thinking) === true || ((_p = this.config.llm.options) == null ? void 0 : _p.thinking) === "enabled" || ((_q = this.config.llm.options) == null ? void 0 : _q.thinking) !== false);
7837
+ const isNativeThinking = isClaude37 && (((_p = this.config.llm.options) == null ? void 0 : _p.thinking) === true || ((_q = this.config.llm.options) == null ? void 0 : _q.thinking) === "enabled" || ((_r = this.config.llm.options) == null ? void 0 : _r.thinking) !== false);
7720
7838
  const modelNameLower = this.config.llm.model.toLowerCase();
7721
7839
  const isReasoningModel = modelNameLower.includes("-r1") || modelNameLower.includes("deepseek-r1") || modelNameLower.includes("reasoning") || modelNameLower.includes("thinking");
7722
- const isSimulatedThinking = !isNativeThinking && (((_r = this.config.llm.options) == null ? void 0 : _r.thinking) === true || ((_s = this.config.llm.options) == null ? void 0 : _s.thinking) === "enabled" || isReasoningModel && ((_t = this.config.llm.options) == null ? void 0 : _t.thinking) !== false);
7840
+ const isSimulatedThinking = !isNativeThinking && (((_s = this.config.llm.options) == null ? void 0 : _s.thinking) === true || ((_t = this.config.llm.options) == null ? void 0 : _t.thinking) === "enabled" || isReasoningModel && ((_u = this.config.llm.options) == null ? void 0 : _u.thinking) !== false);
7723
7841
  let finalRestrictionSuffix = restrictionSuffix;
7724
7842
  if (isSimulatedThinking) {
7725
7843
  finalRestrictionSuffix += "\n\n(IMPORTANT: You must think step-by-step before answering. Write your thinking process inside a `<think>...</think>` block. Write the `<think>` block first, then follow it with your final response. Keep the thinking process thorough and detailed. Example: `<think>Thinking details here...</think>Final answer text here.`)";
@@ -7727,7 +7845,7 @@ ${context}`;
7727
7845
  const hardenedHistory = [...history];
7728
7846
  const userQuestion = { role: "user", content: question + finalRestrictionSuffix };
7729
7847
  const messages = [...hardenedHistory, userQuestion];
7730
- const systemPrompt = (_u = this.config.llm.systemPrompt) != null ? _u : "";
7848
+ const systemPrompt = (_v = this.config.llm.systemPrompt) != null ? _v : "";
7731
7849
  const userPrompt = messages.map((m) => `${m.role}: ${m.content}`).join("\n");
7732
7850
  let fullReply = "";
7733
7851
  let thinkingText = "";
@@ -7838,7 +7956,7 @@ ${context}`;
7838
7956
  }
7839
7957
  yield fullReply;
7840
7958
  }
7841
- const runHallucination = ((_v = this.config.llm.options) == null ? void 0 : _v.hallucinationScoring) === true || this.config.llm.provider !== "ollama" && ((_w = this.config.llm.options) == null ? void 0 : _w.hallucinationScoring) !== false;
7959
+ const runHallucination = ((_w = this.config.llm.options) == null ? void 0 : _w.hallucinationScoring) === true || this.config.llm.provider !== "ollama" && ((_x = this.config.llm.options) == null ? void 0 : _x.hallucinationScoring) !== false;
7842
7960
  if (runHallucination) {
7843
7961
  hallucinationScoringPromise = scoreHallucination(this.llmProvider, fullReply, context).catch(() => void 0);
7844
7962
  }
@@ -7847,7 +7965,7 @@ ${context}`;
7847
7965
  const latency = {
7848
7966
  embedMs: Math.round(embedMs),
7849
7967
  retrieveMs: Math.round(retrieveMs),
7850
- rerankMs: ((_x = this.config.rag) == null ? void 0 : _x.useReranking) ? Math.round(rerankMs) : void 0,
7968
+ rerankMs: arch !== "naive" && (arch === "retrieve-and-rerank" || ((_y = this.config.rag) == null ? void 0 : _y.useReranking)) ? Math.round(rerankMs) : void 0,
7851
7969
  generateMs: Math.round(generateMs),
7852
7970
  totalMs: Math.round(totalMs)
7853
7971
  };
@@ -7860,7 +7978,7 @@ ${context}`;
7860
7978
  totalTokens: promptTokens + completionTokens,
7861
7979
  estimatedCostUsd: estimateCostUsd(promptTokens, completionTokens, this.config.llm.model)
7862
7980
  };
7863
- const awaitHallucination = ((_y = this.config.llm.options) == null ? void 0 : _y.awaitHallucination) === true;
7981
+ const awaitHallucination = ((_z = this.config.llm.options) == null ? void 0 : _z.awaitHallucination) === true;
7864
7982
  const [uiTransformation, hallucinationResult] = yield new __await(Promise.all([
7865
7983
  uiTransformationPromise,
7866
7984
  awaitHallucination ? hallucinationScoringPromise : Promise.resolve(void 0)
@@ -7889,7 +8007,7 @@ ${context}`;
7889
8007
  hallucinationReason: hScore.reason
7890
8008
  } : {});
7891
8009
  const trace = buildTrace(hallucinationResult);
7892
- if ((_z = this.config.telemetry) == null ? void 0 : _z.enabled) {
8010
+ if ((_A = this.config.telemetry) == null ? void 0 : _A.enabled) {
7893
8011
  const telemetryUrl = this.config.telemetry.url || "/api/telemetry";
7894
8012
  const absoluteUrl = telemetryUrl.startsWith("http") ? telemetryUrl : (process.env.NEXT_PUBLIC_APP_URL || `http://localhost:${process.env.PORT || 3e3}`) + telemetryUrl;
7895
8013
  (async () => {
@@ -8165,6 +8283,7 @@ var Retrivora = class {
8165
8283
  this.config.projectId,
8166
8284
  (_a2 = this.config.vectorDb) == null ? void 0 : _a2.provider
8167
8285
  );
8286
+ await LicenseVerifier.verifyIP(this.config.licenseKey);
8168
8287
  } catch (err) {
8169
8288
  throw wrapError(err, "CONFIGURATION_ERROR");
8170
8289
  }
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@retrivora-ai/rag-engine",
3
- "version": "1.9.8",
3
+ "version": "1.9.9",
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
- "license": "MIT",
6
+ "license": "UNLICENSED",
7
7
  "keywords": [
8
8
  "rag",
9
9
  "retrieval-augmented-generation",
@@ -126,6 +126,7 @@
126
126
  "dotenv": "^17.4.2",
127
127
  "eslint": "^9",
128
128
  "eslint-config-next": "16.2.4",
129
+ "next": "16.2.10",
129
130
  "tailwindcss": "^4",
130
131
  "tsup": "^8.5.1",
131
132
  "typescript": "^5"
package/src/app/page.tsx CHANGED
@@ -6,6 +6,7 @@ import { Navbar } from '@/components/Navbar';
6
6
  import { Hero } from '@/components/Hero';
7
7
  import { Lifecycle } from '@/components/Lifecycle';
8
8
  import { ArchitectureCardsSection } from '@/components/ArchitectureCardsSection';
9
+ import { RagPatternsSection } from '@/components/RagPatternsSection';
9
10
  import { Documentation } from '@/components/Documentation';
10
11
  import { ChatWidget } from '@/components/ChatWidget';
11
12
 
@@ -17,6 +18,7 @@ export default function HomePage() {
17
18
  <div className="relative z-10 container mx-auto px-6 py-12">
18
19
  <Hero />
19
20
  <Lifecycle />
21
+ <RagPatternsSection />
20
22
  <ArchitectureCardsSection />
21
23
  <Documentation />
22
24
  </div>
@@ -277,3 +277,227 @@ export const BORDER_RADIUS_MAP: Record<string, string> = {
277
277
  xl: 'rounded-xl',
278
278
  full: 'rounded-3xl',
279
279
  };
280
+
281
+ export interface RagPatternStep {
282
+ label: string;
283
+ type: 'input' | 'process' | 'database' | 'model' | 'output';
284
+ color: string;
285
+ }
286
+
287
+ export interface RagPattern {
288
+ id: string;
289
+ name: string;
290
+ tagline: string;
291
+ description: string;
292
+ pros: string[];
293
+ cons: string[];
294
+ snippet: string;
295
+ color: string;
296
+ flowSteps: RagPatternStep[];
297
+ }
298
+
299
+ export const RAG_PATTERNS: RagPattern[] = [
300
+ {
301
+ id: 'naive',
302
+ name: 'Naive RAG',
303
+ tagline: 'Standard semantic search pipeline',
304
+ description: 'The foundation pattern: splits documents into text chunks, embeddings are stored in a vector database, and relevant context is fetched via direct query similarity to augment the model prompt.',
305
+ pros: ['Very low latency', 'Low resource cost', 'Simple implementation'],
306
+ cons: ['Struggles with complex multi-hop queries', 'No ranking optimization', 'Can return irrelevant context chunks'],
307
+ color: '#d97706', // Amber/Brown
308
+ snippet: `import { Retrivora } from '@retrivora-ai/rag-engine/server';
309
+
310
+ const ai = new Retrivora({
311
+ projectId: 'naive-rag-demo',
312
+ vectorDatabase: {
313
+ provider: 'pinecone',
314
+ indexName: 'knowledge-base',
315
+ },
316
+ workflow: {
317
+ type: 'simple-rag'
318
+ }
319
+ });`,
320
+ flowSteps: [
321
+ { label: 'Documents', type: 'input', color: 'bg-amber-100 text-amber-800 dark:bg-amber-950/40 dark:text-amber-300' },
322
+ { label: 'Chunking', type: 'process', color: 'bg-amber-50 text-amber-700 dark:bg-amber-900/20 dark:text-amber-400' },
323
+ { label: 'Embedding Model', type: 'model', color: 'bg-amber-100 text-amber-900 dark:bg-amber-800/30 dark:text-amber-200' },
324
+ { label: 'Vector Store', type: 'database', color: 'bg-amber-200 text-amber-950 dark:bg-amber-700/40 dark:text-amber-100' },
325
+ { label: 'Context Prompt', type: 'process', color: 'bg-amber-50 text-amber-700 dark:bg-amber-900/20 dark:text-amber-400' },
326
+ { label: 'LLM Generator', type: 'model', color: 'bg-indigo-100 text-indigo-900 dark:bg-indigo-800/30 dark:text-indigo-200' },
327
+ ]
328
+ },
329
+ {
330
+ id: 'retrieve-and-rerank',
331
+ name: 'Retrieve-and-rerank',
332
+ tagline: 'High-precision contextual relevance',
333
+ description: 'Enhances standard RAG by fetching a larger pool of vector candidates and feeding them through a cross-encoder Reranker model. The reranker scores context chunks dynamically relative to query intent, filtering noise.',
334
+ pros: ['Extremely high context precision', 'Better generation accuracy', 'Mitigates hallucination rates'],
335
+ cons: ['Adds slight latency bottleneck (~100-300ms)', 'Higher computational requirements'],
336
+ color: '#2563eb', // Blue
337
+ snippet: `import { Retrivora } from '@retrivora-ai/rag-engine/server';
338
+
339
+ const ai = new Retrivora({
340
+ projectId: 'rerank-rag-demo',
341
+ vectorDatabase: {
342
+ provider: 'pinecone',
343
+ indexName: 'knowledge-base',
344
+ },
345
+ retrieval: {
346
+ strategy: 'contextual-compression',
347
+ useReranking: true, // Enables cross-encoder re-evaluation
348
+ topK: 5,
349
+ }
350
+ });`,
351
+ flowSteps: [
352
+ { label: 'Query Input', type: 'input', color: 'bg-blue-100 text-blue-800 dark:bg-blue-950/40 dark:text-blue-300' },
353
+ { label: 'Vector Retrieval', type: 'database', color: 'bg-blue-200 text-blue-950 dark:bg-blue-700/40 dark:text-blue-100' },
354
+ { label: 'Reranker Model', type: 'model', color: 'bg-indigo-100 text-indigo-950 dark:bg-indigo-700/40 dark:text-indigo-100' },
355
+ { label: 'Filtered Context', type: 'process', color: 'bg-blue-50 text-blue-700 dark:bg-blue-900/20 dark:text-blue-400' },
356
+ { label: 'Generative Model', type: 'model', color: 'bg-violet-100 text-violet-900 dark:bg-violet-800/30 dark:text-violet-200' },
357
+ ]
358
+ },
359
+ {
360
+ id: 'multimodal',
361
+ name: 'Multimodal RAG',
362
+ tagline: 'Search and reason across text and media',
363
+ description: 'Ingests both unstructured text documents and visual/audio/structured assets. It queries multi-modal embeddings, feeding retrieved visuals and matched context fragments to multimodal LLMs (like Gemini or Claude) to support diagrams, tables, and media outputs.',
364
+ pros: ['Handles images, PDFs, charts, audio', 'Deeper context retrieval', 'Generates visual answers'],
365
+ cons: ['Multimodal embeddings are computationally expensive', 'Higher token payload sizes'],
366
+ color: '#7c3aed', // Purple
367
+ snippet: `import { Retrivora } from '@retrivora-ai/rag-engine/server';
368
+
369
+ const ai = new Retrivora({
370
+ projectId: 'multimodal-rag-demo',
371
+ llm: {
372
+ provider: 'gemini',
373
+ model: 'gemini-2.5-flash', // Multimodal reasoning model
374
+ },
375
+ embedding: {
376
+ provider: 'gemini',
377
+ model: 'text-embedding-004',
378
+ },
379
+ workflow: {
380
+ type: 'multimodal-rag'
381
+ }
382
+ });`,
383
+ flowSteps: [
384
+ { label: 'Multi-modal Docs', type: 'input', color: 'bg-purple-100 text-purple-800 dark:bg-purple-950/40 dark:text-purple-300' },
385
+ { label: 'Multi-modal Embed', type: 'model', color: 'bg-purple-50 text-purple-700 dark:bg-purple-900/20 dark:text-purple-400' },
386
+ { label: 'Vector Store', type: 'database', color: 'bg-purple-200 text-purple-950 dark:bg-purple-700/40 dark:text-purple-100' },
387
+ { label: 'Media Context', type: 'process', color: 'bg-purple-100 text-purple-950 dark:bg-purple-800/40 dark:text-purple-100' },
388
+ { label: 'Multimodal LLM', type: 'model', color: 'bg-violet-100 text-violet-900 dark:bg-violet-800/30 dark:text-violet-200' },
389
+ ]
390
+ },
391
+ {
392
+ id: 'graph',
393
+ name: 'Graph RAG',
394
+ tagline: 'Entity-relationship semantic reasoning',
395
+ description: 'Builds a knowledge graph structure from raw documents using an LLM extractor. Entity-to-entity and entity-to-document relationships are resolved, allowing queries to retrieve structured semantic contexts (nodes & relationships) to resolve structural, relational, and hierarchy-based questions.',
396
+ pros: ['Excellent for tracing connections', 'Resolves hierarchy and relationships', 'Grounded fact validation'],
397
+ cons: ['Heavy write-time pipeline ingestion cost', 'Requires graph database setup'],
398
+ color: '#059669', // Emerald
399
+ snippet: `import { Retrivora } from '@retrivora-ai/rag-engine/server';
400
+
401
+ const ai = new Retrivora({
402
+ projectId: 'graph-rag-demo',
403
+ graphDb: {
404
+ provider: 'neo4j',
405
+ options: { uri: 'neo4j://localhost:7687' },
406
+ },
407
+ workflow: {
408
+ type: 'graph-rag'
409
+ }
410
+ });`,
411
+ flowSteps: [
412
+ { label: 'Documents', type: 'input', color: 'bg-emerald-100 text-emerald-800 dark:bg-emerald-950/40 dark:text-emerald-300' },
413
+ { label: 'LLM Extractor', type: 'model', color: 'bg-emerald-50 text-emerald-700 dark:bg-emerald-900/20 dark:text-emerald-400' },
414
+ { label: 'Graph Database', type: 'database', color: 'bg-emerald-200 text-emerald-950 dark:bg-emerald-700/40 dark:text-emerald-100' },
415
+ { label: 'Relation Search', type: 'process', color: 'bg-emerald-100 text-emerald-950 dark:bg-emerald-800/40 dark:text-emerald-100' },
416
+ { label: 'LLM Reasoner', type: 'model', color: 'bg-indigo-100 text-indigo-900 dark:bg-indigo-800/30 dark:text-indigo-200' },
417
+ ]
418
+ },
419
+ {
420
+ id: 'hybrid',
421
+ name: 'Hybrid RAG',
422
+ tagline: 'Best of both worlds: Vector + Graph',
423
+ description: 'Queries both a vector database for semantic match proximity and a graph database for topological linkages. It joins vector search results and sub-graph entity contexts into a unified prompt, resolving complex interconnected schemas.',
424
+ pros: ['Unparalleled query coverage', 'Combines semantic proximity and graph relationships', 'Robust grounding'],
425
+ cons: ['Most complex RAG configuration', 'Double database query overhead'],
426
+ color: '#d97706', // Orange
427
+ snippet: `import { Retrivora } from '@retrivora-ai/rag-engine/server';
428
+
429
+ const ai = new Retrivora({
430
+ projectId: 'hybrid-rag-demo',
431
+ vectorDatabase: { provider: 'mongodb', indexName: 'default' },
432
+ graphDb: { provider: 'neo4j', options: { uri: 'neo4j://...' } },
433
+ workflow: {
434
+ type: 'hybrid-rag'
435
+ }
436
+ });`,
437
+ flowSteps: [
438
+ { label: 'Query', type: 'input', color: 'bg-amber-100 text-amber-800 dark:bg-amber-950/40 dark:text-amber-300' },
439
+ { label: 'Vector Store', type: 'database', color: 'bg-orange-100 text-orange-950 dark:bg-orange-700/40 dark:text-orange-100' },
440
+ { label: 'Graph Database', type: 'database', color: 'bg-emerald-100 text-emerald-950 dark:bg-emerald-700/40 dark:text-emerald-100' },
441
+ { label: 'Unified Context', type: 'process', color: 'bg-amber-50 text-amber-700 dark:bg-amber-900/20 dark:text-amber-400' },
442
+ { label: 'LLM Reasoner', type: 'model', color: 'bg-indigo-100 text-indigo-900 dark:bg-indigo-800/30 dark:text-indigo-200' },
443
+ ]
444
+ },
445
+ {
446
+ id: 'agentic-router',
447
+ name: 'Agentic RAG (Router)',
448
+ tagline: 'Dynamic intent-based query routing',
449
+ description: 'Uses an intelligent fast router agent to analyze the intent of the incoming query. The router dynamically decides whether to fetch data from the Vector DB, query a Graph DB, fallback to web search, or trigger external API tools.',
450
+ pros: ['Highly adaptive workflow', 'Saves tokens on simple queries', 'Automatically invokes external API tools'],
451
+ cons: ['Adds slight routing classification latency', 'Dependent on router accuracy'],
452
+ color: '#0891b2', // Cyan
453
+ snippet: `import { Retrivora } from '@retrivora-ai/rag-engine/server';
454
+
455
+ const ai = new Retrivora({
456
+ projectId: 'agentic-router-demo',
457
+ workflow: {
458
+ type: 'agentic-router'
459
+ }
460
+ });`,
461
+ flowSteps: [
462
+ { label: 'User Query', type: 'input', color: 'bg-cyan-100 text-cyan-800 dark:bg-cyan-950/40 dark:text-cyan-300' },
463
+ { label: 'Router Agent', type: 'model', color: 'bg-indigo-100 text-indigo-900 dark:bg-indigo-800/30 dark:text-indigo-200' },
464
+ { label: 'Vector / Graph / Tools', type: 'database', color: 'bg-cyan-200 text-cyan-950 dark:bg-cyan-700/40 dark:text-cyan-100' },
465
+ { label: 'Selected Context', type: 'process', color: 'bg-cyan-50 text-cyan-700 dark:bg-cyan-900/20 dark:text-cyan-400' },
466
+ { label: 'LLM Generator', type: 'model', color: 'bg-violet-100 text-violet-900 dark:bg-violet-800/30 dark:text-violet-200' },
467
+ ]
468
+ },
469
+ {
470
+ id: 'multi-agent',
471
+ name: 'Agent RAG (Multi-Agent)',
472
+ tagline: 'Collaborative swarm-based problem solving',
473
+ description: 'Deploys a supervisor agent that coordinates a group of specialized worker agents (e.g., search agent, tool executor agent, web crawler agent). Agents collaborate, pass information, check each other\'s facts, and compile a final answer.',
474
+ pros: ['Excellent for complex research tasks', 'Self-correcting query pipelines', 'Multi-step action sequences'],
475
+ cons: ['High latency (requires multiple LLM cycles)', 'Higher cost per query', 'Complex state synchronization'],
476
+ color: '#ec4899', // Pink
477
+ snippet: `import { Retrivora } from '@retrivora-ai/rag-engine/server';
478
+
479
+ const ai = new Retrivora({
480
+ projectId: 'multi-agent-demo',
481
+ workflow: {
482
+ type: 'multi-agent'
483
+ },
484
+ mcpServers: [
485
+ {
486
+ name: 'search-engine',
487
+ transport: 'stdio',
488
+ command: 'npx',
489
+ args: ['-y', '@modelcontextprotocol/server-web-search']
490
+ }
491
+ ]
492
+ });`,
493
+ flowSteps: [
494
+ { label: 'Goal Query', type: 'input', color: 'bg-pink-100 text-pink-800 dark:bg-pink-950/40 dark:text-pink-300' },
495
+ { label: 'Supervisor Agent', type: 'model', color: 'bg-pink-200 text-pink-950 dark:bg-pink-800/30 dark:text-pink-100' },
496
+ { label: 'Specialist Agents', type: 'model', color: 'bg-indigo-100 text-indigo-900 dark:bg-indigo-900/30 dark:text-indigo-200' },
497
+ { label: 'Tools / Vector DBs', type: 'database', color: 'bg-pink-200 text-pink-950 dark:bg-pink-700/40 dark:text-pink-100' },
498
+ { label: 'Consensus Context', type: 'process', color: 'bg-pink-50 text-pink-700 dark:bg-pink-900/20 dark:text-pink-400' },
499
+ { label: 'Final Output', type: 'output', color: 'bg-indigo-600 text-white shadow-sm' },
500
+ ]
501
+ }
502
+ ];
503
+
@@ -182,7 +182,7 @@ export interface RAGConfig {
182
182
  /** Characters used to split text, in order of priority */
183
183
  separators?: string[];
184
184
  /** Overall RAG architecture pattern */
185
- architecture?: 'simple' | 'graph' | 'hybrid' | 'agentic';
185
+ architecture?: 'simple' | 'graph' | 'hybrid' | 'agentic' | 'naive' | 'retrieve-and-rerank' | 'multimodal' | 'agentic-router' | 'multi-agent';
186
186
  /** Chunking strategy to use during ingestion */
187
187
  chunkingStrategy?: 'recursive' | 'markdown' | 'semantic' | 'llamaindex';
188
188
  /** Whether to use query transformation (e.g. HyDE) */
@@ -249,7 +249,7 @@ export interface RetrievalConfig {
249
249
 
250
250
  export interface WorkflowConfig {
251
251
  /** High-level workflow selector from the SDK prompt. */
252
- type?: 'simple-rag' | 'rag' | 'hybrid-rag' | 'graph-rag' | 'agentic-rag' | 'agentic';
252
+ type?: 'simple-rag' | 'rag' | 'hybrid-rag' | 'graph-rag' | 'agentic-rag' | 'agentic' | 'naive-rag' | 'retrieve-and-rerank' | 'multimodal-rag' | 'agentic-router' | 'multi-agent-rag' | 'multi-agent';
253
253
  /** Future workflow/provider-specific options. */
254
254
  options?: Record<string, unknown>;
255
255
  }