@retrivora-ai/rag-engine 1.9.3 → 1.9.7

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 (69) hide show
  1. package/README.md +59 -7
  2. package/dist/{ILLMProvider-Bw2A28nU.d.mts → ILLMProvider-Bhk6zJOK.d.mts} +43 -7
  3. package/dist/{ILLMProvider-Bw2A28nU.d.ts → ILLMProvider-Bhk6zJOK.d.ts} +43 -7
  4. package/dist/handlers/index.d.mts +2 -2
  5. package/dist/handlers/index.d.ts +2 -2
  6. package/dist/handlers/index.js +737 -237
  7. package/dist/handlers/index.mjs +736 -237
  8. package/dist/index-B9J_XEh0.d.ts +187 -0
  9. package/dist/index-BJ4cd-t5.d.mts +187 -0
  10. package/dist/{index-B70ZLkfG.d.mts → index-Bu7T6xgr.d.ts} +20 -3
  11. package/dist/{index-DVu-mkAM.d.ts → index-C3SVtPYg.d.mts} +20 -3
  12. package/dist/index.css +237 -10
  13. package/dist/index.d.mts +13 -5
  14. package/dist/index.d.ts +13 -5
  15. package/dist/index.js +365 -164
  16. package/dist/index.mjs +350 -158
  17. package/dist/server.d.mts +15 -94
  18. package/dist/server.d.ts +15 -94
  19. package/dist/server.js +850 -239
  20. package/dist/server.mjs +839 -238
  21. package/package.json +2 -4
  22. package/src/app/api/chat/route.ts +2 -2
  23. package/src/app/api/health/route.ts +3 -2
  24. package/src/app/api/ingest/route.ts +3 -2
  25. package/src/app/api/suggestions/route.ts +3 -2
  26. package/src/app/api/upload/route.ts +3 -2
  27. package/src/app/constants.tsx +168 -148
  28. package/src/app/layout.tsx +5 -18
  29. package/src/app/types.ts +17 -17
  30. package/src/components/ChatWidget.tsx +3 -1
  31. package/src/components/ChatWindow.tsx +5 -1
  32. package/src/components/DocViewer.tsx +71 -5
  33. package/src/components/Documentation.tsx +74 -11
  34. package/src/components/MessageBubble.tsx +39 -2
  35. package/src/components/ThinkingBlock.tsx +75 -0
  36. package/src/components/VisualizationRenderer.tsx +27 -1
  37. package/src/components/constants.tsx +275 -0
  38. package/src/config/RagConfig.ts +47 -0
  39. package/src/config/constants.ts +1 -0
  40. package/src/config/serverConfig.ts +25 -0
  41. package/src/core/ConfigResolver.ts +73 -22
  42. package/src/core/ConfigValidator.ts +2 -1
  43. package/src/core/Pipeline.ts +226 -68
  44. package/src/core/ProviderRegistry.ts +16 -7
  45. package/src/core/QueryProcessor.ts +38 -4
  46. package/src/core/Retrivora.ts +91 -0
  47. package/src/core/VectorPlugin.ts +62 -8
  48. package/src/exceptions/index.ts +111 -0
  49. package/src/handlers/index.ts +73 -0
  50. package/src/hooks/useRagChat.ts +30 -5
  51. package/src/index.ts +27 -1
  52. package/src/lib/plugin.ts +24 -0
  53. package/src/llm/LLMFactory.ts +8 -4
  54. package/src/llm/providers/AnthropicProvider.ts +70 -20
  55. package/src/llm/providers/GeminiProvider.ts +14 -15
  56. package/src/llm/providers/OllamaProvider.ts +13 -16
  57. package/src/llm/providers/OpenAIProvider.ts +9 -14
  58. package/src/llm/providers/UniversalLLMAdapter.ts +5 -5
  59. package/src/llm/utils.ts +46 -0
  60. package/src/providers/vectordb/MongoDBProvider.ts +9 -4
  61. package/src/providers/vectordb/MultiTablePostgresProvider.ts +45 -13
  62. package/src/rag/EntityExtractor.ts +2 -2
  63. package/src/rag/Reranker.ts +9 -16
  64. package/src/server.ts +30 -1
  65. package/src/types/chat.ts +9 -0
  66. package/src/types/props.ts +38 -1
  67. package/src/utils/UITransformer.ts +73 -4
  68. package/dist/DocumentChunker-Dh9TvmGG.d.mts +0 -45
  69. package/dist/DocumentChunker-Dh9TvmGG.d.ts +0 -45
package/dist/server.js CHANGED
@@ -10,9 +10,6 @@ var __getProtoOf = Object.getPrototypeOf;
10
10
  var __hasOwnProp = Object.prototype.hasOwnProperty;
11
11
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
12
12
  var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : /* @__PURE__ */ Symbol.for("Symbol." + name);
13
- var __typeError = (msg) => {
14
- throw TypeError(msg);
15
- };
16
13
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
17
14
  var __spreadValues = (a, b) => {
18
15
  for (var prop in b || (b = {}))
@@ -77,34 +74,6 @@ var __asyncGenerator = (__this, __arguments, generator) => {
77
74
  }, method = (k, call, wait, clear) => it[k] = (x) => (call = new Promise((yes, no, run) => (run = () => resume(k, x, yes, no), q ? q.then(run) : run())), clear = () => q === wait && (q = 0), q = wait = call.then(clear, clear), call), q, it = {};
78
75
  return generator = generator.apply(__this, __arguments), it[__knownSymbol("asyncIterator")] = () => it, method("next"), method("throw"), method("return"), it;
79
76
  };
80
- var __yieldStar = (value) => {
81
- var obj = value[__knownSymbol("asyncIterator")], isAwait = false, method, it = {};
82
- if (obj == null) {
83
- obj = value[__knownSymbol("iterator")]();
84
- method = (k) => it[k] = (x) => obj[k](x);
85
- } else {
86
- obj = obj.call(value);
87
- method = (k) => it[k] = (v) => {
88
- if (isAwait) {
89
- isAwait = false;
90
- if (k === "throw") throw v;
91
- return v;
92
- }
93
- isAwait = true;
94
- return {
95
- done: false,
96
- value: new __await(new Promise((resolve) => {
97
- var x = obj[k](v);
98
- if (!(x instanceof Object)) __typeError("Object expected");
99
- resolve(x);
100
- }), 1)
101
- };
102
- };
103
- }
104
- return it[__knownSymbol("iterator")] = () => it, method("next"), "throw" in obj ? method("throw") : it.throw = (x) => {
105
- throw x;
106
- }, "return" in obj && method("return"), it;
107
- };
108
77
  var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")]) ? it.call(obj) : (obj = obj[__knownSymbol("iterator")](), it = {}, method = (key, fn) => (fn = obj[key]) && (it[key] = (arg) => new Promise((yes, no, done) => (arg = fn.call(obj, arg), done = arg.done, Promise.resolve(arg.value).then((value) => yes({ value, done }), no)))), method("next"), method("return"), it);
109
78
 
110
79
  // src/utils/templateUtils.ts
@@ -661,6 +630,11 @@ var init_MultiTablePostgresProvider = __esm({
661
630
  CREATE INDEX IF NOT EXISTS ${this.uploadTable}_embedding_idx
662
631
  ON ${this.uploadTable}
663
632
  USING hnsw (embedding vector_cosine_ops)
633
+ `);
634
+ await client.query(`
635
+ CREATE INDEX IF NOT EXISTS "${this.uploadTable}_fts_idx"
636
+ ON "${this.uploadTable}"
637
+ USING gin (to_tsvector('english', content))
664
638
  `);
665
639
  const res = await client.query(`
666
640
  SELECT table_name
@@ -731,6 +705,11 @@ var init_MultiTablePostgresProvider = __esm({
731
705
  CREATE INDEX IF NOT EXISTS "${tableName}_embedding_idx"
732
706
  ON "${tableName}"
733
707
  USING hnsw (embedding vector_cosine_ops)
708
+ `);
709
+ await client.query(`
710
+ CREATE INDEX IF NOT EXISTS "${tableName}_fts_idx"
711
+ ON "${tableName}"
712
+ USING gin (to_tsvector('english', content))
734
713
  `);
735
714
  if (!this.tables.includes(tableName)) {
736
715
  this.tables.push(tableName);
@@ -822,8 +801,11 @@ var init_MultiTablePostgresProvider = __esm({
822
801
  const paramIdx = baseOffset + filterParams.length;
823
802
  const synonyms = (_a3 = FIELD_SYNONYMS[key]) != null ? _a3 : [];
824
803
  const keysToCheck = [key, ...synonyms];
825
- const coalesceExprs = keysToCheck.map((k) => `LOWER(metadata->>'${k}')`);
826
- return `COALESCE(${coalesceExprs.join(", ")}) = LOWER($${paramIdx})`;
804
+ const coalesceExprs = keysToCheck.flatMap((k) => [
805
+ `metadata->>'${k}'`,
806
+ `to_jsonb(t)->>'${k}'`
807
+ ]);
808
+ return `COALESCE(${coalesceExprs.map((expr) => `LOWER(${expr})`).join(", ")}) = LOWER($${paramIdx})`;
827
809
  });
828
810
  whereClause = `WHERE ${conditions.join(" AND ")}`;
829
811
  }
@@ -834,16 +816,35 @@ var init_MultiTablePostgresProvider = __esm({
834
816
  CASE WHEN LOWER(val) IN (${entityHints.map((h) => `'${h.replace(/'/g, "''")}'`).join(", ")})
835
817
  THEN 1.0 ELSE 0.0 END
836
818
  ), 0)
837
- FROM jsonb_each_text(to_jsonb(t)) AS kv(key, val)
819
+ FROM jsonb_each_text(COALESCE(v.metadata, k.metadata)) AS kv(key, val)
838
820
  WHERE key IN (${this.searchFields.map((f) => `'${f}'`).join(", ")})
839
821
  ) * 3.0` : "";
840
822
  sqlQuery = `
841
- SELECT *,
842
- (1 - (embedding <=> $1::vector)) AS vector_score,
843
- COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), to_tsquery('english', $2)), 0) AS keyword_score,
844
- ((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
845
- FROM "${table}" t
846
- ${whereClause}
823
+ WITH vector_search AS (
824
+ SELECT *, (1 - (embedding <=> $1::vector)) AS vector_score
825
+ FROM "${table}" t
826
+ ${whereClause}
827
+ ORDER BY embedding <=> $1::vector ASC
828
+ LIMIT ${tableLimit}
829
+ ),
830
+ keyword_search AS (
831
+ SELECT *, COALESCE(ts_rank(to_tsvector('english', content), to_tsquery('english', $2)), 0) AS keyword_score
832
+ FROM "${table}" t
833
+ WHERE ${whereClause ? whereClause.replace("WHERE", "") : "TRUE"}
834
+ AND to_tsvector('english', content) @@ to_tsquery('english', $2)
835
+ ORDER BY keyword_score DESC
836
+ LIMIT ${tableLimit}
837
+ )
838
+ SELECT
839
+ COALESCE(v.id, k.id) AS id,
840
+ COALESCE(v.namespace, k.namespace) AS namespace,
841
+ COALESCE(v.content, k.content) AS content,
842
+ COALESCE(v.metadata, k.metadata) AS metadata,
843
+ COALESCE(v.vector_score, 0) AS vector_score,
844
+ COALESCE(k.keyword_score, 0) AS keyword_score,
845
+ (COALESCE(v.vector_score, 0) + COALESCE(k.keyword_score, 0) * 2.0 ${exactNameScoreExpr}) AS hybrid_score
846
+ FROM vector_search v
847
+ FULL OUTER JOIN keyword_search k ON v.id = k.id
847
848
  ORDER BY hybrid_score DESC
848
849
  LIMIT ${tableLimit}
849
850
  `;
@@ -854,7 +855,7 @@ var init_MultiTablePostgresProvider = __esm({
854
855
  (1 - (embedding <=> $1::vector)) AS hybrid_score
855
856
  FROM "${table}" t
856
857
  ${whereClause}
857
- ORDER BY hybrid_score DESC
858
+ ORDER BY embedding <=> $1::vector ASC
858
859
  LIMIT ${tableLimit}
859
860
  `;
860
861
  params = [vectorLiteral, ...filterParams];
@@ -1060,7 +1061,11 @@ var init_MongoDBProvider = __esm({
1060
1061
  if (key === "namespace") {
1061
1062
  vectorSearchFilter.namespace = value;
1062
1063
  } else {
1063
- matchFilter[key] = value;
1064
+ if (typeof value === "string") {
1065
+ matchFilter[key] = { $regex: new RegExp(`^${value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "i") };
1066
+ } else {
1067
+ matchFilter[key] = value;
1068
+ }
1064
1069
  }
1065
1070
  }
1066
1071
  const pipeline = [
@@ -2066,14 +2071,17 @@ var init_SimpleGraphProvider = __esm({
2066
2071
  var server_exports = {};
2067
2072
  __export(server_exports, {
2068
2073
  AnthropicProvider: () => AnthropicProvider,
2074
+ AuthenticationException: () => AuthenticationException,
2069
2075
  BaseVectorProvider: () => BaseVectorProvider,
2070
2076
  BatchProcessor: () => BatchProcessor,
2071
2077
  ChromaDBProvider: () => ChromaDBProvider,
2072
2078
  ConfigBuilder: () => ConfigBuilder,
2073
2079
  ConfigResolver: () => ConfigResolver,
2074
2080
  ConfigValidator: () => ConfigValidator,
2081
+ ConfigurationException: () => ConfigurationException,
2075
2082
  DocumentChunker: () => DocumentChunker,
2076
2083
  DocumentParser: () => DocumentParser,
2084
+ EmbeddingFailedException: () => EmbeddingFailedException,
2077
2085
  EmbeddingStrategy: () => EmbeddingStrategy,
2078
2086
  EmbeddingStrategyResolver: () => EmbeddingStrategyResolver,
2079
2087
  LLMFactory: () => LLMFactory,
@@ -2088,9 +2096,14 @@ __export(server_exports, {
2088
2096
  Pipeline: () => Pipeline,
2089
2097
  PostgreSQLProvider: () => PostgreSQLProvider,
2090
2098
  ProviderHealthCheck: () => ProviderHealthCheck,
2099
+ ProviderNotFoundException: () => ProviderNotFoundException,
2091
2100
  ProviderRegistry: () => ProviderRegistry,
2092
2101
  QdrantProvider: () => QdrantProvider,
2102
+ RateLimitException: () => RateLimitException,
2093
2103
  RedisProvider: () => RedisProvider,
2104
+ RetrievalException: () => RetrievalException,
2105
+ Retrivora: () => Retrivora,
2106
+ RetrivoraError: () => RetrivoraError,
2094
2107
  UniversalLLMAdapter: () => UniversalLLMAdapter,
2095
2108
  UniversalVectorProvider: () => UniversalVectorProvider,
2096
2109
  VECTOR_PROFILES: () => VECTOR_PROFILES,
@@ -2100,13 +2113,15 @@ __export(server_exports, {
2100
2113
  createFromPreset: () => createFromPreset,
2101
2114
  createHealthHandler: () => createHealthHandler,
2102
2115
  createIngestHandler: () => createIngestHandler,
2116
+ createRagHandler: () => createRagHandler,
2103
2117
  createStreamHandler: () => createStreamHandler,
2104
2118
  createUploadHandler: () => createUploadHandler,
2105
2119
  getRagConfig: () => getRagConfig,
2106
2120
  sseErrorFrame: () => sseErrorFrame,
2107
2121
  sseFrame: () => sseFrame,
2108
2122
  sseMetaFrame: () => sseMetaFrame,
2109
- sseTextFrame: () => sseTextFrame
2123
+ sseTextFrame: () => sseTextFrame,
2124
+ wrapError: () => wrapError
2110
2125
  });
2111
2126
  module.exports = __toCommonJS(server_exports);
2112
2127
 
@@ -2181,7 +2196,7 @@ function getRagConfig(baseConfig, env = process.env) {
2181
2196
  return getEnvConfig(env, baseConfig);
2182
2197
  }
2183
2198
  function getEnvConfig(env = process.env, base) {
2184
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa, _ya, _za, _Aa, _Ba, _Ca, _Da, _Ea, _Fa, _Ga;
2199
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa, _ya, _za, _Aa, _Ba, _Ca, _Da, _Ea, _Fa, _Ga, _Ha, _Ia, _Ja;
2185
2200
  const projectId = (_c = (_b = (_a = readString(env, "RAG_PROJECT_ID")) != null ? _a : readString(env, "NEXT_PUBLIC_PROJECT_ID")) != null ? _b : base == null ? void 0 : base.projectId) != null ? _c : "__default__";
2186
2201
  const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
2187
2202
  const llmProvider = readEnum(env, "LLM_PROVIDER", "openai", LLM_PROVIDERS);
@@ -2251,7 +2266,7 @@ function getEnvConfig(env = process.env, base) {
2251
2266
  rest: "default",
2252
2267
  custom: "default"
2253
2268
  };
2254
- return {
2269
+ return __spreadValues({
2255
2270
  projectId,
2256
2271
  vectorDb: {
2257
2272
  provider: vectorProvider,
@@ -2267,7 +2282,9 @@ function getEnvConfig(env = process.env, base) {
2267
2282
  maxTokens: readNumber(env, "LLM_MAX_TOKENS", 4096),
2268
2283
  temperature: readNumber(env, "LLM_TEMPERATURE", 0.7),
2269
2284
  options: {
2270
- profile: readString(env, "LLM_UNIVERSAL_PROFILE")
2285
+ profile: readString(env, "LLM_UNIVERSAL_PROFILE"),
2286
+ thinking: readString(env, "LLM_THINKING") === "true" || readString(env, "LLM_THINKING") === "enabled" ? true : readString(env, "LLM_THINKING") === "false" ? false : void 0,
2287
+ thinkingBudget: env.LLM_THINKING_BUDGET ? parseInt(env.LLM_THINKING_BUDGET, 10) : void 0
2271
2288
  }
2272
2289
  },
2273
2290
  embedding: {
@@ -2299,9 +2316,34 @@ function getEnvConfig(env = process.env, base) {
2299
2316
  topK: readNumber(env, "RAG_TOP_K", 5),
2300
2317
  scoreThreshold: readNumber(env, "RAG_SCORE_THRESHOLD", 0),
2301
2318
  chunkSize: readNumber(env, "RAG_CHUNK_SIZE", 1e3),
2302
- chunkOverlap: readNumber(env, "RAG_CHUNK_OVERLAP", 200)
2319
+ chunkOverlap: readNumber(env, "RAG_CHUNK_OVERLAP", 200),
2320
+ filterableFields: (_Ha = readString(env, "RAG_FILTERABLE_FIELDS")) == null ? void 0 : _Ha.split(",").map((f) => f.trim()),
2321
+ // Query pipeline toggles — read from .env.local
2322
+ useQueryTransformation: readString(env, "RAG_USE_QUERY_TRANSFORMATION") === "true",
2323
+ useReranking: readString(env, "RAG_USE_RERANKING") === "true",
2324
+ useGraphRetrieval: readString(env, "RAG_USE_GRAPH_RETRIEVAL") === "true",
2325
+ architecture: (_Ia = readString(env, "RAG_ARCHITECTURE")) != null ? _Ia : "simple",
2326
+ chunkingStrategy: (_Ja = readString(env, "RAG_CHUNKING_STRATEGY")) != null ? _Ja : "recursive",
2327
+ uiMapping: (() => {
2328
+ const raw = readString(env, "RAG_UI_MAPPING");
2329
+ if (!raw) return void 0;
2330
+ try {
2331
+ return JSON.parse(raw);
2332
+ } catch (e) {
2333
+ return void 0;
2334
+ }
2335
+ })()
2303
2336
  }
2304
- };
2337
+ }, readString(env, "GRAPH_DB_PROVIDER") ? {
2338
+ graphDb: {
2339
+ provider: readString(env, "GRAPH_DB_PROVIDER"),
2340
+ options: {
2341
+ uri: readString(env, "GRAPH_DB_URI"),
2342
+ username: readString(env, "GRAPH_DB_USERNAME"),
2343
+ password: readString(env, "GRAPH_DB_PASSWORD")
2344
+ }
2345
+ }
2346
+ } : {});
2305
2347
  }
2306
2348
 
2307
2349
  // src/core/ConfigResolver.ts
@@ -2330,6 +2372,20 @@ var ConfigResolver = class {
2330
2372
  rag: hostConfig.rag ? __spreadValues(__spreadValues({}, envConfig.rag), hostConfig.rag) : envConfig.rag
2331
2373
  });
2332
2374
  }
2375
+ /**
2376
+ * Resolves the public SDK config shape used by `new Retrivora({...})`.
2377
+ * Supports aliases from the product prompt while preserving existing env
2378
+ * fallback behavior.
2379
+ */
2380
+ static resolveUniversal(hostConfig, env = process.env) {
2381
+ var _a;
2382
+ if (!hostConfig) return this.resolve(void 0, env);
2383
+ const normalized = __spreadProps(__spreadValues({}, hostConfig), {
2384
+ vectorDb: (_a = hostConfig.vectorDb) != null ? _a : hostConfig.vectorDatabase,
2385
+ rag: this.mergeRetrievalWorkflow(hostConfig.rag, hostConfig.retrieval, hostConfig.workflow)
2386
+ });
2387
+ return this.resolve(normalized, env);
2388
+ }
2333
2389
  /**
2334
2390
  * Validates the configuration for required fields.
2335
2391
  */
@@ -2344,10 +2400,53 @@ var ConfigResolver = class {
2344
2400
  throw new Error("[ConfigResolver] llm.provider is required");
2345
2401
  }
2346
2402
  }
2403
+ static mergeRetrievalWorkflow(rag, retrieval, workflow) {
2404
+ var _a, _b, _c, _d, _e;
2405
+ if (!rag && !retrieval && !workflow) return void 0;
2406
+ const normalized = __spreadValues({}, rag != null ? rag : {});
2407
+ if (retrieval) {
2408
+ normalized.topK = (_a = retrieval.topK) != null ? _a : normalized.topK;
2409
+ normalized.scoreThreshold = (_b = retrieval.scoreThreshold) != null ? _b : normalized.scoreThreshold;
2410
+ normalized.useReranking = (_c = retrieval.useReranking) != null ? _c : normalized.useReranking;
2411
+ if (retrieval.strategy === "hybrid") normalized.architecture = (_d = normalized.architecture) != null ? _d : "hybrid";
2412
+ if (retrieval.strategy === "agentic") normalized.architecture = "agentic";
2413
+ if (retrieval.strategy === "contextual-compression") normalized.useReranking = true;
2414
+ }
2415
+ if (workflow == null ? void 0 : workflow.type) {
2416
+ const type = workflow.type;
2417
+ if (type === "agentic" || type === "agentic-rag") normalized.architecture = "agentic";
2418
+ else if (type === "hybrid-rag") normalized.architecture = "hybrid";
2419
+ else if (type === "graph-rag") {
2420
+ normalized.architecture = "graph";
2421
+ normalized.useGraphRetrieval = true;
2422
+ } else if (type === "simple-rag" || type === "rag") {
2423
+ normalized.architecture = (_e = normalized.architecture) != null ? _e : "simple";
2424
+ }
2425
+ }
2426
+ return normalized;
2427
+ }
2347
2428
  };
2348
2429
 
2349
2430
  // src/llm/providers/OpenAIProvider.ts
2350
2431
  var import_openai = __toESM(require("openai"));
2432
+
2433
+ // src/llm/utils.ts
2434
+ function buildSystemContent(systemPrompt, context) {
2435
+ const noContext = !context || context.trim() === "" || context.trim() === "No relevant context found.";
2436
+ if (systemPrompt.includes("{{context}}")) {
2437
+ return systemPrompt.replace("{{context}}", noContext ? "" : context);
2438
+ }
2439
+ if (noContext) {
2440
+ return systemPrompt;
2441
+ }
2442
+ return `${systemPrompt}
2443
+
2444
+ ---
2445
+ Context:
2446
+ ${context}`;
2447
+ }
2448
+
2449
+ // src/llm/providers/OpenAIProvider.ts
2351
2450
  var OpenAIProvider = class {
2352
2451
  constructor(llmConfig, embeddingConfig) {
2353
2452
  if (!llmConfig.apiKey) throw new Error("[OpenAIProvider] llmConfig.apiKey is required");
@@ -2411,16 +2510,10 @@ var OpenAIProvider = class {
2411
2510
  }
2412
2511
  async chat(messages, context, options) {
2413
2512
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
2414
- const resolvedSystemPrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : `You are a helpful assistant. Answer questions based on the provided context.
2415
-
2416
- Context:
2417
- ${context}`;
2513
+ const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
2418
2514
  const systemMessage = {
2419
2515
  role: "system",
2420
- content: resolvedSystemPrompt.includes("{{context}}") ? resolvedSystemPrompt.replace("{{context}}", context) : (options == null ? void 0 : options.systemPrompt) ? resolvedSystemPrompt : `${resolvedSystemPrompt}
2421
-
2422
- Context:
2423
- ${context}`
2516
+ content: buildSystemContent(basePrompt, context)
2424
2517
  };
2425
2518
  const formattedMessages = [
2426
2519
  systemMessage,
@@ -2441,16 +2534,10 @@ ${context}`
2441
2534
  chatStream(messages, context, options) {
2442
2535
  return __asyncGenerator(this, null, function* () {
2443
2536
  var _a, _b, _c, _d, _e, _f, _g, _h;
2444
- const resolvedSystemPrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : `You are a helpful assistant. Answer questions based on the provided context.
2445
-
2446
- Context:
2447
- ${context}`;
2537
+ const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
2448
2538
  const systemMessage = {
2449
2539
  role: "system",
2450
- content: resolvedSystemPrompt.includes("{{context}}") ? resolvedSystemPrompt.replace("{{context}}", context) : (options == null ? void 0 : options.systemPrompt) ? resolvedSystemPrompt : `${resolvedSystemPrompt}
2451
-
2452
- Context:
2453
- ${context}`
2540
+ content: buildSystemContent(basePrompt, context)
2454
2541
  };
2455
2542
  const formattedMessages = [
2456
2543
  systemMessage,
@@ -2571,58 +2658,87 @@ var AnthropicProvider = class {
2571
2658
  };
2572
2659
  }
2573
2660
  async chat(messages, context, options) {
2574
- var _a, _b, _c, _d;
2575
- const resolvedPrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : `You are a helpful assistant. Use the context below to answer the user's question accurately.
2576
-
2577
- Context:
2578
- ${context}`;
2579
- const system = resolvedPrompt.includes("{{context}}") ? resolvedPrompt.replace("{{context}}", context) : (options == null ? void 0 : options.systemPrompt) ? resolvedPrompt : `${resolvedPrompt}
2580
-
2581
- Context:
2582
- ${context}`;
2661
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
2662
+ const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the context below to answer the user's question accurately.";
2663
+ const system = buildSystemContent(basePrompt, context);
2583
2664
  const anthropicMessages = messages.map((m) => ({
2584
2665
  role: m.role === "assistant" ? "assistant" : "user",
2585
2666
  content: m.content
2586
2667
  }));
2587
- const response = await this.client.messages.create({
2668
+ const isClaude37 = this.llmConfig.model.includes("claude-3-7-sonnet");
2669
+ const isThinkingEnabled = ((_c = this.llmConfig.options) == null ? void 0 : _c.thinking) === true || ((_d = this.llmConfig.options) == null ? void 0 : _d.thinking) === "enabled" || isClaude37 && ((_e = this.llmConfig.options) == null ? void 0 : _e.thinking) !== false;
2670
+ const extraParams = {};
2671
+ if (isThinkingEnabled && isClaude37) {
2672
+ extraParams.betas = ["interleaved-thinking-2025-05-14"];
2673
+ const maxTokens = (_g = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g : 4096;
2674
+ const budget = Math.min(
2675
+ typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
2676
+ maxTokens - 1
2677
+ );
2678
+ extraParams.thinking = {
2679
+ type: "enabled",
2680
+ budget_tokens: budget
2681
+ };
2682
+ extraParams.max_tokens = Math.max(maxTokens, budget + 1024);
2683
+ }
2684
+ const response = await this.client.messages.create(__spreadValues({
2588
2685
  model: this.llmConfig.model,
2589
- max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
2686
+ max_tokens: (_k = (_j = options == null ? void 0 : options.maxTokens) != null ? _j : this.llmConfig.maxTokens) != null ? _k : 1024,
2590
2687
  system,
2591
2688
  messages: anthropicMessages
2592
- });
2593
- const block = response.content[0];
2594
- return block.type === "text" ? block.text : "";
2689
+ }, extraParams));
2690
+ let reply = "";
2691
+ for (const block of response.content) {
2692
+ if (block.type === "text") {
2693
+ reply += block.text;
2694
+ }
2695
+ }
2696
+ return reply;
2595
2697
  }
2596
2698
  chatStream(messages, context, options) {
2597
2699
  return __asyncGenerator(this, null, function* () {
2598
- var _a, _b, _c, _d;
2599
- const resolvedPrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : `You are a helpful assistant. Use the context below to answer the user's question accurately.
2600
-
2601
- Context:
2602
- ${context}`;
2603
- const system = resolvedPrompt.includes("{{context}}") ? resolvedPrompt.replace("{{context}}", context) : (options == null ? void 0 : options.systemPrompt) ? resolvedPrompt : `${resolvedPrompt}
2604
-
2605
- Context:
2606
- ${context}`;
2700
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
2701
+ const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the context below to answer the user's question accurately.";
2702
+ const system = buildSystemContent(basePrompt, context);
2607
2703
  const anthropicMessages = messages.map((m) => ({
2608
2704
  role: m.role === "assistant" ? "assistant" : "user",
2609
2705
  content: m.content
2610
2706
  }));
2611
- const stream = yield new __await(this.client.messages.create({
2707
+ const isClaude37 = this.llmConfig.model.includes("claude-3-7-sonnet");
2708
+ const isThinkingEnabled = ((_c = this.llmConfig.options) == null ? void 0 : _c.thinking) === true || ((_d = this.llmConfig.options) == null ? void 0 : _d.thinking) === "enabled" || isClaude37 && ((_e = this.llmConfig.options) == null ? void 0 : _e.thinking) !== false;
2709
+ const extraParams = {};
2710
+ if (isThinkingEnabled && isClaude37) {
2711
+ extraParams.betas = ["interleaved-thinking-2025-05-14"];
2712
+ const maxTokens = (_g = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g : 4096;
2713
+ const budget = Math.min(
2714
+ typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
2715
+ maxTokens - 1
2716
+ );
2717
+ extraParams.thinking = {
2718
+ type: "enabled",
2719
+ budget_tokens: budget
2720
+ };
2721
+ extraParams.max_tokens = Math.max(maxTokens, budget + 1024);
2722
+ }
2723
+ const stream = yield new __await(this.client.messages.create(__spreadValues({
2612
2724
  model: this.llmConfig.model,
2613
- max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
2725
+ max_tokens: (_k = (_j = options == null ? void 0 : options.maxTokens) != null ? _j : this.llmConfig.maxTokens) != null ? _k : 1024,
2614
2726
  system,
2615
2727
  messages: anthropicMessages,
2616
2728
  stream: true
2617
- }));
2729
+ }, extraParams)));
2618
2730
  if (!stream) {
2619
2731
  throw new Error("[AnthropicProvider] messages.create stream is undefined");
2620
2732
  }
2621
2733
  try {
2622
2734
  for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
2623
2735
  const chunk = temp.value;
2624
- if (chunk.type === "content_block_delta" && chunk.delta.type === "text_delta") {
2625
- yield chunk.delta.text;
2736
+ if (chunk.type === "content_block_delta") {
2737
+ if (chunk.delta.type === "text_delta") {
2738
+ yield chunk.delta.text;
2739
+ } else if (chunk.delta.type === "thinking_delta") {
2740
+ yield `\0THINKING\0${chunk.delta.thinking}`;
2741
+ }
2626
2742
  }
2627
2743
  }
2628
2744
  } catch (temp) {
@@ -2666,9 +2782,10 @@ ${context}`;
2666
2782
  var import_axios = __toESM(require("axios"));
2667
2783
  var OllamaProvider = class {
2668
2784
  constructor(llmConfig, embeddingConfig) {
2669
- var _a;
2785
+ var _a, _b;
2670
2786
  const baseURL = (_a = llmConfig.baseUrl) != null ? _a : "http://localhost:11434";
2671
- this.http = import_axios.default.create({ baseURL, timeout: 12e4 });
2787
+ const timeout = Number((_b = llmConfig.options) == null ? void 0 : _b.timeout) || 3e5;
2788
+ this.http = import_axios.default.create({ baseURL, timeout });
2672
2789
  this.llmConfig = llmConfig;
2673
2790
  this.embeddingConfig = embeddingConfig;
2674
2791
  }
@@ -2724,14 +2841,15 @@ var OllamaProvider = class {
2724
2841
  };
2725
2842
  }
2726
2843
  async chat(messages, context, options) {
2727
- var _a, _b, _c, _d;
2728
- const system = this.buildSystemPrompt(context, options == null ? void 0 : options.systemPrompt);
2844
+ var _a, _b, _c, _d, _e, _f;
2845
+ const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the provided context to answer the user's question.";
2846
+ const system = buildSystemContent(basePrompt, context);
2729
2847
  const { data } = await this.http.post("/api/chat", {
2730
2848
  model: this.llmConfig.model,
2731
2849
  stream: false,
2732
2850
  options: {
2733
- temperature: (_b = (_a = options == null ? void 0 : options.temperature) != null ? _a : this.llmConfig.temperature) != null ? _b : 0.7,
2734
- num_predict: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024
2851
+ temperature: (_d = (_c = options == null ? void 0 : options.temperature) != null ? _c : this.llmConfig.temperature) != null ? _d : 0.7,
2852
+ num_predict: (_f = (_e = options == null ? void 0 : options.maxTokens) != null ? _e : this.llmConfig.maxTokens) != null ? _f : 1024
2735
2853
  },
2736
2854
  messages: [
2737
2855
  { role: "system", content: system },
@@ -2742,14 +2860,15 @@ var OllamaProvider = class {
2742
2860
  }
2743
2861
  chatStream(messages, context, options) {
2744
2862
  return __asyncGenerator(this, null, function* () {
2745
- var _a, _b, _c, _d, _e, _f;
2746
- const system = this.buildSystemPrompt(context, options == null ? void 0 : options.systemPrompt);
2863
+ var _a, _b, _c, _d, _e, _f, _g, _h;
2864
+ const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the provided context to answer the user's question.";
2865
+ const system = buildSystemContent(basePrompt, context);
2747
2866
  const response = yield new __await(this.http.post("/api/chat", {
2748
2867
  model: this.llmConfig.model,
2749
2868
  stream: true,
2750
2869
  options: {
2751
- temperature: (_b = (_a = options == null ? void 0 : options.temperature) != null ? _a : this.llmConfig.temperature) != null ? _b : 0.7,
2752
- num_predict: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024
2870
+ temperature: (_d = (_c = options == null ? void 0 : options.temperature) != null ? _c : this.llmConfig.temperature) != null ? _d : 0.7,
2871
+ num_predict: (_f = (_e = options == null ? void 0 : options.maxTokens) != null ? _e : this.llmConfig.maxTokens) != null ? _f : 1024
2753
2872
  },
2754
2873
  messages: [
2755
2874
  { role: "system", content: system },
@@ -2771,7 +2890,7 @@ var OllamaProvider = class {
2771
2890
  if (!line.trim()) continue;
2772
2891
  try {
2773
2892
  const json = JSON.parse(line);
2774
- if ((_e = json.message) == null ? void 0 : _e.content) {
2893
+ if ((_g = json.message) == null ? void 0 : _g.content) {
2775
2894
  yield json.message.content;
2776
2895
  }
2777
2896
  if (json.done) return;
@@ -2793,26 +2912,12 @@ var OllamaProvider = class {
2793
2912
  if (lineBuffer.trim()) {
2794
2913
  try {
2795
2914
  const json = JSON.parse(lineBuffer);
2796
- if ((_f = json.message) == null ? void 0 : _f.content) yield json.message.content;
2915
+ if ((_h = json.message) == null ? void 0 : _h.content) yield json.message.content;
2797
2916
  } catch (e) {
2798
2917
  }
2799
2918
  }
2800
2919
  });
2801
2920
  }
2802
- buildSystemPrompt(context, overridePrompt) {
2803
- var _a;
2804
- if (overridePrompt) {
2805
- return overridePrompt;
2806
- }
2807
- const systemPrompt = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Use the provided context to answer the user's question.
2808
-
2809
- Context:
2810
- ${context}`;
2811
- return systemPrompt.includes("{{context}}") ? systemPrompt.replace("{{context}}", context) : `${systemPrompt}
2812
-
2813
- Context:
2814
- ${context}`;
2815
- }
2816
2921
  async embed(text, options) {
2817
2922
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
2818
2923
  const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "nomic-embed-text";
@@ -2959,21 +3064,6 @@ var GeminiProvider = class {
2959
3064
  var _a, _b;
2960
3065
  return sanitizeModel((_b = optionsModel != null ? optionsModel : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _b : DEFAULT_EMBEDDING_MODEL);
2961
3066
  }
2962
- /**
2963
- * Build the system instruction string, inserting the RAG context either via
2964
- * the `{{context}}` placeholder or by appending it.
2965
- */
2966
- buildSystemInstruction(context) {
2967
- var _a;
2968
- const base = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Answer questions based on the provided context.
2969
-
2970
- Context:
2971
- ${context}`;
2972
- return base.includes("{{context}}") ? base.replace("{{context}}", context) : `${base}
2973
-
2974
- Context:
2975
- ${context}`;
2976
- }
2977
3067
  /**
2978
3068
  * Convert ChatMessage[] to the Gemini contents format.
2979
3069
  *
@@ -2992,16 +3082,17 @@ ${context}`;
2992
3082
  // ILLMProvider — chat
2993
3083
  // -------------------------------------------------------------------------
2994
3084
  async chat(messages, context, options) {
2995
- var _a, _b, _c, _d;
3085
+ var _a, _b, _c, _d, _e, _f;
3086
+ const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
2996
3087
  const model = this.client.getGenerativeModel({
2997
3088
  model: this.llmConfig.model,
2998
- systemInstruction: this.buildSystemInstruction(context)
3089
+ systemInstruction: buildSystemContent(basePrompt, context)
2999
3090
  });
3000
3091
  const result = await model.generateContent({
3001
3092
  contents: this.buildGeminiContents(messages),
3002
3093
  generationConfig: {
3003
- temperature: (_b = (_a = options == null ? void 0 : options.temperature) != null ? _a : this.llmConfig.temperature) != null ? _b : DEFAULT_TEMPERATURE,
3004
- maxOutputTokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : DEFAULT_MAX_TOKENS,
3094
+ temperature: (_d = (_c = options == null ? void 0 : options.temperature) != null ? _c : this.llmConfig.temperature) != null ? _d : DEFAULT_TEMPERATURE,
3095
+ maxOutputTokens: (_f = (_e = options == null ? void 0 : options.maxTokens) != null ? _e : this.llmConfig.maxTokens) != null ? _f : DEFAULT_MAX_TOKENS,
3005
3096
  stopSequences: options == null ? void 0 : options.stop
3006
3097
  }
3007
3098
  });
@@ -3009,16 +3100,17 @@ ${context}`;
3009
3100
  }
3010
3101
  chatStream(messages, context, options) {
3011
3102
  return __asyncGenerator(this, null, function* () {
3012
- var _a, _b, _c, _d;
3103
+ var _a, _b, _c, _d, _e, _f;
3104
+ const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
3013
3105
  const model = this.client.getGenerativeModel({
3014
3106
  model: this.llmConfig.model,
3015
- systemInstruction: this.buildSystemInstruction(context)
3107
+ systemInstruction: buildSystemContent(basePrompt, context)
3016
3108
  });
3017
3109
  const result = yield new __await(model.generateContentStream({
3018
3110
  contents: this.buildGeminiContents(messages),
3019
3111
  generationConfig: {
3020
- temperature: (_b = (_a = options == null ? void 0 : options.temperature) != null ? _a : this.llmConfig.temperature) != null ? _b : DEFAULT_TEMPERATURE,
3021
- maxOutputTokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : DEFAULT_MAX_TOKENS,
3112
+ temperature: (_d = (_c = options == null ? void 0 : options.temperature) != null ? _c : this.llmConfig.temperature) != null ? _d : DEFAULT_TEMPERATURE,
3113
+ maxOutputTokens: (_f = (_e = options == null ? void 0 : options.maxTokens) != null ? _e : this.llmConfig.maxTokens) != null ? _f : DEFAULT_MAX_TOKENS,
3022
3114
  stopSequences: options == null ? void 0 : options.stop
3023
3115
  }
3024
3116
  }));
@@ -3385,6 +3477,78 @@ ${context != null ? context : "None"}` },
3385
3477
  }
3386
3478
  };
3387
3479
 
3480
+ // src/exceptions/index.ts
3481
+ var RetrivoraError = class extends Error {
3482
+ constructor(message, code, details) {
3483
+ super(message);
3484
+ this.name = new.target.name;
3485
+ this.code = code;
3486
+ this.details = details;
3487
+ }
3488
+ };
3489
+ var ProviderNotFoundException = class extends RetrivoraError {
3490
+ constructor(providerType, provider, details) {
3491
+ super(`Unsupported ${providerType} provider: ${provider}`, "PROVIDER_NOT_FOUND", details);
3492
+ }
3493
+ };
3494
+ var EmbeddingFailedException = class extends RetrivoraError {
3495
+ constructor(message = "Embedding generation failed", details) {
3496
+ super(message, "EMBEDDING_FAILED", details);
3497
+ }
3498
+ };
3499
+ var RetrievalException = class extends RetrivoraError {
3500
+ constructor(message = "Retrieval failed", details) {
3501
+ super(message, "RETRIEVAL_FAILED", details);
3502
+ }
3503
+ };
3504
+ var RateLimitException = class extends RetrivoraError {
3505
+ constructor(message = "Provider rate limit exceeded", details) {
3506
+ super(message, "RATE_LIMITED", details);
3507
+ }
3508
+ };
3509
+ var ConfigurationException = class extends RetrivoraError {
3510
+ constructor(message, details) {
3511
+ super(message, "CONFIGURATION_ERROR", details);
3512
+ }
3513
+ };
3514
+ var AuthenticationException = class extends RetrivoraError {
3515
+ constructor(message = "Provider authentication failed", details) {
3516
+ super(message, "AUTHENTICATION_ERROR", details);
3517
+ }
3518
+ };
3519
+ function wrapError(err, defaultCode, defaultMessage) {
3520
+ var _a;
3521
+ if (err instanceof RetrivoraError) {
3522
+ return err;
3523
+ }
3524
+ const error = err;
3525
+ const message = (error == null ? void 0 : error.message) || defaultMessage || String(err);
3526
+ const status = (error == null ? void 0 : error.status) || (error == null ? void 0 : error.statusCode) || ((_a = error == null ? void 0 : error.response) == null ? void 0 : _a.status);
3527
+ const code = error == null ? void 0 : error.code;
3528
+ if (status === 429 || /rate[- ]?limit/i.test(message) || code === "RATE_LIMIT_EXCEEDED") {
3529
+ return new RateLimitException(message, err);
3530
+ }
3531
+ if (status === 401 || status === 403 || /unauthorized|auth|api[- ]?key/i.test(message) || code === "INVALID_API_KEY") {
3532
+ return new AuthenticationException(message, err);
3533
+ }
3534
+ switch (defaultCode) {
3535
+ case "PROVIDER_NOT_FOUND":
3536
+ return new ProviderNotFoundException("provider", message, err);
3537
+ case "EMBEDDING_FAILED":
3538
+ return new EmbeddingFailedException(message, err);
3539
+ case "RETRIEVAL_FAILED":
3540
+ return new RetrievalException(message, err);
3541
+ case "RATE_LIMITED":
3542
+ return new RateLimitException(message, err);
3543
+ case "CONFIGURATION_ERROR":
3544
+ return new ConfigurationException(message, err);
3545
+ case "AUTHENTICATION_ERROR":
3546
+ return new AuthenticationException(message, err);
3547
+ default:
3548
+ return new RetrivoraError(message, defaultCode, err);
3549
+ }
3550
+ }
3551
+
3388
3552
  // src/llm/LLMFactory.ts
3389
3553
  var customProviders = /* @__PURE__ */ new Map();
3390
3554
  var LLMFactory = class _LLMFactory {
@@ -3430,7 +3594,7 @@ var LLMFactory = class _LLMFactory {
3430
3594
  ];
3431
3595
  }
3432
3596
  static create(llmConfig, embeddingConfig) {
3433
- var _a, _b;
3597
+ var _a, _b, _c;
3434
3598
  switch (llmConfig.provider) {
3435
3599
  case "openai":
3436
3600
  return new OpenAIProvider(llmConfig, embeddingConfig);
@@ -3453,8 +3617,13 @@ var LLMFactory = class _LLMFactory {
3453
3617
  if (llmConfig.baseUrl || ((_b = llmConfig.options) == null ? void 0 : _b.baseUrl)) {
3454
3618
  return new UniversalLLMAdapter(llmConfig);
3455
3619
  }
3456
- throw new Error(
3457
- `[LLMFactory] Unknown provider "${llmConfig.provider}". Built-in providers: ${_LLMFactory.listProviders().join(", ")}. Register a custom provider with LLMFactory.register().`
3620
+ throw new ProviderNotFoundException(
3621
+ "llm",
3622
+ (_c = llmConfig.provider) != null ? _c : "undefined",
3623
+ {
3624
+ message: `Unknown provider "${llmConfig.provider}". Register a custom provider with LLMFactory.register().`,
3625
+ available: _LLMFactory.listProviders()
3626
+ }
3458
3627
  );
3459
3628
  }
3460
3629
  }
@@ -3585,7 +3754,7 @@ var ProviderRegistry = class {
3585
3754
  return UniversalVectorProvider2;
3586
3755
  }
3587
3756
  default:
3588
- throw new Error(`Unsupported vector provider: ${provider}`);
3757
+ throw new ProviderNotFoundException("vector", provider);
3589
3758
  }
3590
3759
  }
3591
3760
  static async createVectorProvider(config) {
@@ -3603,12 +3772,18 @@ var ProviderRegistry = class {
3603
3772
  return new SimpleGraphProvider2(config);
3604
3773
  }
3605
3774
  default:
3606
- throw new Error(`Unsupported graph provider: ${provider}`);
3775
+ throw new ProviderNotFoundException("graph", provider);
3607
3776
  }
3608
3777
  }
3609
3778
  static createLLMProvider(llmConfig, embeddingConfig) {
3610
3779
  return LLMFactory.create(llmConfig, embeddingConfig);
3611
3780
  }
3781
+ static registerLLMProvider(name, factory) {
3782
+ LLMFactory.register(name, factory);
3783
+ }
3784
+ static createEmbeddingProvider(embeddingConfig) {
3785
+ return LLMFactory.createEmbeddingProvider(embeddingConfig);
3786
+ }
3612
3787
  };
3613
3788
  ProviderRegistry.vectorProviders = {};
3614
3789
  ProviderRegistry.graphProviders = {};
@@ -3755,8 +3930,8 @@ var ConfigValidator = class {
3755
3930
  const errorItems = errors.filter((e) => e.severity === "error");
3756
3931
  if (errorItems.length > 0) {
3757
3932
  const message = errorItems.map((e) => `${e.field}: ${e.message}${e.suggestion ? ` (${e.suggestion})` : ""}`).join("\n ");
3758
- throw new Error(`[ConfigValidator] Configuration validation failed:
3759
- ${message}`);
3933
+ throw new ConfigurationException(`[ConfigValidator] Configuration validation failed:
3934
+ ${message}`, errorItems);
3760
3935
  }
3761
3936
  }
3762
3937
  };
@@ -3943,20 +4118,17 @@ var Reranker = class {
3943
4118
  }
3944
4119
  try {
3945
4120
  const topN = matches.slice(0, 10);
3946
- const prompt = `You are a relevance ranking expert.
3947
- Given the following user query and a list of retrieved document chunks, rank the chunks by relevance to the query.
3948
- Return the result as a comma-separated list of document indices in order of relevance, from most relevant to least relevant.
3949
- Use the indices provided in brackets like [0], [1], etc.
3950
- Only return the indices (e.g., "2,0,1"), nothing else. Do not include brackets in the output.
3951
-
3952
- Query: "${query}"
4121
+ const response = await llm.chat(
4122
+ [{ role: "user", content: `Query: "${query}"
3953
4123
 
3954
4124
  Documents:
3955
- ${topN.map((m, i) => `[${i}] ${m.content.replace(/\n/g, " ")}`).join("\n")}`;
3956
- const response = await llm.chat(
3957
- [{ role: "user", content: prompt }],
4125
+ ${topN.map((m, i) => `[${i}] ${m.content.replace(/\n/g, " ")}`).join("\n")}` }],
3958
4126
  "",
3959
- { temperature: 0, maxTokens: 50 }
4127
+ {
4128
+ systemPrompt: 'You are a relevance ranking expert. Given the user query and a list of retrieved document chunks, rank the chunks by relevance to the query. Return the result as a comma-separated list of document indices in order of relevance, from most relevant to least relevant. Use the indices provided in brackets like [0], [1], etc. Only return the indices (e.g., "2,0,1"), nothing else. Do not include brackets in the output.',
4129
+ temperature: 0,
4130
+ maxTokens: 50
4131
+ }
3960
4132
  );
3961
4133
  const cleanedResponse = response.trim().replace(/[\[\]\s]/g, "");
3962
4134
  const rankedIndices = cleanedResponse.split(",").map(Number).filter((n) => !isNaN(n));
@@ -4468,6 +4640,18 @@ var QueryProcessor = class {
4468
4640
  }, normalizedField ? { field: normalizedField } : {}));
4469
4641
  }
4470
4642
  };
4643
+ const activeValidFields = validFields.length > 0 ? validFields : ["brand", "category", "price", "rating", "stock", "stock_quantity", "status", "name", "title"];
4644
+ const resolveValidField = (fieldStr) => {
4645
+ const cleaned = this.normalizeHintValue(fieldStr).replace(/\b(?:provide|show|get|give|list|all|the|a|an|of|organizations?|companies?|records?|items?|whose|with|having|where|that|which|have|has|is|are|was|were)\b/gi, " ").replace(/\s+/g, " ").trim();
4646
+ const comparable = (v) => v.toLowerCase().replace(/[^a-z0-9]/g, "");
4647
+ const cleanedComparable = comparable(cleaned);
4648
+ if (!cleanedComparable) return null;
4649
+ const matchedField = activeValidFields.find((fieldName) => {
4650
+ const candidate = comparable(fieldName);
4651
+ return candidate === cleanedComparable || candidate.includes(cleanedComparable) || cleanedComparable.includes(candidate);
4652
+ });
4653
+ return matchedField != null ? matchedField : null;
4654
+ };
4471
4655
  for (const match of question.matchAll(/["']([^"']{2,100})["']/g)) {
4472
4656
  addHint(match[1]);
4473
4657
  }
@@ -4492,7 +4676,13 @@ var QueryProcessor = class {
4492
4676
  const field = match[1];
4493
4677
  const value = match[2];
4494
4678
  if (field && !this.isLikelyPromptPhrase(field)) {
4495
- addHint(value, field);
4679
+ const resolvedField = resolveValidField(field);
4680
+ if (resolvedField) {
4681
+ addHint(value, resolvedField);
4682
+ } else {
4683
+ addHint(value);
4684
+ addHint(field);
4685
+ }
4496
4686
  }
4497
4687
  }
4498
4688
  if (validFields.length > 0) {
@@ -4538,12 +4728,16 @@ var QueryProcessor = class {
4538
4728
  ];
4539
4729
  for (const pattern of fieldValuePatterns) {
4540
4730
  for (const match of question.matchAll(pattern)) {
4541
- const field = this.normalizeHintValue((_c = match[1]) != null ? _c : "");
4731
+ const field = (_c = match[1]) != null ? _c : "";
4542
4732
  const value = (_d = match[2]) != null ? _d : "";
4543
- if (field && !this.isLikelyPromptPhrase(field)) {
4544
- addHint(value, field);
4733
+ const resolvedField = resolveValidField(field);
4734
+ if (resolvedField) {
4735
+ addHint(value, resolvedField);
4545
4736
  } else {
4546
4737
  addHint(value);
4738
+ if (field && !this.isLikelyPromptPhrase(field)) {
4739
+ addHint(field);
4740
+ }
4547
4741
  }
4548
4742
  }
4549
4743
  }
@@ -4770,7 +4964,7 @@ var LLMRouter = class {
4770
4964
 
4771
4965
  // src/utils/UITransformer.ts
4772
4966
  init_synonyms();
4773
- var UITransformer = class {
4967
+ var UITransformer = class _UITransformer {
4774
4968
  // ─── Public Entry Points ─────────────────────────────────────────────────
4775
4969
  /**
4776
4970
  * Heuristic-only transform (no LLM required).
@@ -4832,7 +5026,7 @@ var UITransformer = class {
4832
5026
  static async analyzeAndDecide(query, sources, llm) {
4833
5027
  let intent;
4834
5028
  try {
4835
- intent = await this.detectIntent(query, llm);
5029
+ intent = await this.detectIntent(query, llm, sources);
4836
5030
  console.debug("[UITransformer] Detected intent:", intent);
4837
5031
  } catch (err) {
4838
5032
  console.warn("[UITransformer] Intent detection failed; using heuristic.", err);
@@ -4850,11 +5044,23 @@ var UITransformer = class {
4850
5044
  try {
4851
5045
  const context = this.buildContextSummary(sources);
4852
5046
  const systemPrompt = this.buildVisualizationSystemPrompt();
5047
+ const profile = this.profileData(sources);
5048
+ const schemaContext = `
5049
+ RETRIEVED DATA SCHEMA:
5050
+ - Numeric fields (measures): ${profile.numericFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
5051
+ - Category fields (dimensions): ${profile.categoricalFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
5052
+ - Date fields (temporal): ${profile.dateFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
5053
+ - Boolean fields: ${profile.booleanFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
5054
+ - Text/Other fields: ${profile.fields.filter((f) => f.kind === "text").map((f) => f.key).join(", ") || "None"}
5055
+ `;
4853
5056
  const userPrompt = [
4854
5057
  `USER QUESTION: ${query}`,
4855
5058
  "",
4856
5059
  `DETECTED INTENT (JSON): ${JSON.stringify(intent)}`,
4857
5060
  "",
5061
+ `RETRIEVED DATA SCHEMA:`,
5062
+ schemaContext,
5063
+ "",
4858
5064
  "RETRIEVED DATA (JSON):",
4859
5065
  context
4860
5066
  ].join("\n");
@@ -4865,6 +5071,20 @@ var UITransformer = class {
4865
5071
  );
4866
5072
  const parsed = this.parseTransformationResponse(rawResponse);
4867
5073
  if (parsed) {
5074
+ let isCompatible = true;
5075
+ if (parsed.type === "line_chart" && (profile.dateFields.length === 0 || profile.numericFields.length === 0)) {
5076
+ isCompatible = false;
5077
+ } else if (["bar_chart", "horizontal_bar", "pie_chart", "donut_chart"].includes(parsed.type) && (profile.categoricalFields.length === 0 && profile.numericFields.length === 0)) {
5078
+ isCompatible = false;
5079
+ } else if (parsed.type === "scatter_plot" && profile.numericFields.length < 2) {
5080
+ isCompatible = false;
5081
+ } else if (parsed.type === "metric_card" && profile.numericFields.length === 0) {
5082
+ isCompatible = false;
5083
+ }
5084
+ if (!isCompatible) {
5085
+ console.warn(`[UITransformer] LLM chose incompatible visualization type "${parsed.type}" for retrieved schema. Falling back to heuristic.`);
5086
+ return this.transform(query, sources, void 0, void 0, intent);
5087
+ }
4868
5088
  const intentAllowsTable = intent.wantsExplicitTable || ["tabular", "table", "geographic"].includes(intent.visualizationHint);
4869
5089
  const intentWantsPieLikeChart = ["pie_chart", "donut_chart"].includes(intent.recommendedChart) || ["composition", "category_breakdown"].includes(intent.visualizationHint);
4870
5090
  if (parsed.type === "table" && !intentAllowsTable) {
@@ -4894,7 +5114,26 @@ var UITransformer = class {
4894
5114
  * - The intent object can be reused across both the heuristic and LLM paths.
4895
5115
  * - It is easy to unit-test intent detection in isolation.
4896
5116
  */
4897
- static async detectIntent(query, llm) {
5117
+ static async detectIntent(query, llm, sources) {
5118
+ let schemaProfileText = "";
5119
+ if (sources && sources.length > 0) {
5120
+ const profile = this.profileData(sources);
5121
+ const hasProducts = sources.some((item) => this.isProductData(item));
5122
+ schemaProfileText = `
5123
+ RETRIEVED DATA SCHEMA:
5124
+ - Numeric fields (measures): ${profile.numericFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
5125
+ - Category fields (dimensions): ${profile.categoricalFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
5126
+ - Date fields (temporal): ${profile.dateFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
5127
+ - Boolean fields: ${profile.booleanFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
5128
+ - Text fields: ${profile.fields.filter((f) => f.kind === "text").map((f) => f.key).join(", ") || "None"}
5129
+
5130
+ Please choose visualizationHint and recommendedChart dynamically based on the available schema.
5131
+ - Do NOT recommend "trend" or "line_chart" if there are no Date fields.
5132
+ - Do NOT recommend numeric-dependent visualizations (like bar_chart, line_chart, pie_chart, scatter_plot, histogram, metric_card) if there are no Numeric fields. Fall back to tabular/table or text.
5133
+ - If there are multiple metadata fields but no clear categories or numbers, "tabular"/"table" is a highly accurate default.
5134
+ ${hasProducts ? `- Note: The retrieved data matches product/catalog structure. If the user query is looking for, exploring, searching, browsing, or listing products/items, you MUST recommend visualizationHint: "product_browse" and recommendedChart: "text".` : ""}
5135
+ `;
5136
+ }
4898
5137
  const systemPrompt = `You are an intent classifier for a product-search RAG system.
4899
5138
  Given a user query, return ONLY a valid JSON object with this exact shape \u2014 no prose, no markdown:
4900
5139
 
@@ -4930,8 +5169,11 @@ RULES:
4930
5169
  - isTemporal: true if time words appear (trend, historical, over time, last year, monthly, etc.)
4931
5170
  - isComparison: true if user compares, ranks, or contrasts entities or categories.
4932
5171
  - language: detect from the query text itself; default "en" if uncertain.`;
5172
+ const userPrompt = `QUERY: ${query}${schemaProfileText ? `
5173
+
5174
+ ${schemaProfileText}` : ""}`;
4933
5175
  const rawResponse = await llm.chat(
4934
- [{ role: "user", content: `QUERY: ${query}` }],
5176
+ [{ role: "user", content: userPrompt }],
4935
5177
  "",
4936
5178
  { systemPrompt, temperature: 0 }
4937
5179
  );
@@ -5374,10 +5616,21 @@ RULES:
5374
5616
  const hasEntityTerms = /\b(organization|organisations?|organizations?|company|companies|employee|employees|staff|headcount|workforce)\b/.test(q);
5375
5617
  return asksForRecords && (hasNumericPredicate || hasEntityTerms);
5376
5618
  }
5619
+ /** @internal kept private for transform() internal logic */
5377
5620
  static isProductQuery(query) {
5621
+ return _UITransformer._productQueryTest(query);
5622
+ }
5623
+ /**
5624
+ * Public entry-point for external callers (e.g. Pipeline)
5625
+ * to check whether a query maps to product_browse without triggering an LLM call.
5626
+ */
5627
+ static isProductQueryPublic(query) {
5628
+ return _UITransformer._productQueryTest(query);
5629
+ }
5630
+ static _productQueryTest(query) {
5378
5631
  const q = query.toLowerCase();
5379
5632
  const productTerms = /\b(product|products|item|items|sku|catalog|catalogue|price|prices|brand|model|stock|inventory|in stock|out of stock|buy|shop)\b/.test(q);
5380
- const productAction = /\b(recommend|suggest|describe|description|detail|details|about|show|find|search|browse|list)\b/.test(q);
5633
+ const productAction = /\b(recommend|suggest|describe|description|detail|details|about|show|find|search|browse|list|explore|exploring)\b/.test(q);
5381
5634
  const nonProductEntityTerms = /\b(organization|organisations?|organizations?|company|companies|employee|employees|staff|headcount|workforce)\b/.test(q);
5382
5635
  return productTerms && productAction && !nonProductEntityTerms;
5383
5636
  }
@@ -6150,23 +6403,19 @@ function estimateCostUsd(promptTokens, completionTokens, model) {
6150
6403
  async function scoreHallucination(llm, answer, context) {
6151
6404
  const maxContextChars = 3e3;
6152
6405
  const truncatedContext = context.length > maxContextChars ? context.slice(0, maxContextChars) + "\n...[truncated]" : context;
6153
- 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.
6154
-
6155
- CONTEXT:
6406
+ try {
6407
+ const raw = await llm.chat(
6408
+ [{ role: "user", content: `CONTEXT:
6156
6409
  ${truncatedContext}
6157
6410
 
6158
6411
  ANSWER:
6159
- ${answer}
6160
-
6161
- Return ONLY a valid JSON object with no markdown fences:
6162
- {"score": <float 0-1>, "reason": "<one sentence>"}
6163
-
6164
- Where score 0 = fully grounded in context, score 1 = likely hallucinated or unsupported.`;
6165
- try {
6166
- const raw = await llm.chat(
6167
- [{ role: "user", content: prompt }],
6412
+ ${answer}` }],
6168
6413
  "",
6169
- { temperature: 0, maxTokens: 120 }
6414
+ {
6415
+ systemPrompt: '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. Return ONLY a valid JSON object with no markdown fences: {"score": <float 0-1>, "reason": "<one sentence>"} where score 0 = fully grounded in context, score 1 = likely hallucinated or unsupported.',
6416
+ temperature: 0,
6417
+ maxTokens: 120
6418
+ }
6170
6419
  );
6171
6420
  const jsonMatch = raw.match(/\{[\s\S]*\}/);
6172
6421
  if (!jsonMatch) return void 0;
@@ -6226,7 +6475,10 @@ var Pipeline = class {
6226
6475
  - For product descriptions, summarize customer-facing details only. Do NOT list internal catalog fields such as Handle, Body (HTML), Vendor, Type, Tags, Published, Option, Variant, SKU, or raw metadata labels.
6227
6476
  - Do NOT try to format product lists as tables.
6228
6477
  `;
6229
- this.config.llm.systemPrompt = chartInstruction;
6478
+ const userPromptPrefix = this.config.llm.systemPrompt ? `${this.config.llm.systemPrompt}
6479
+
6480
+ ` : "";
6481
+ this.config.llm.systemPrompt = `${userPromptPrefix}${chartInstruction}`;
6230
6482
  this.vectorDB = await ProviderRegistry.createVectorProvider(this.config.vectorDb);
6231
6483
  this.llmRouter = new LLMRouter(this.config);
6232
6484
  const { llmProvider: resolvedLLM, embeddingProvider } = await EmbeddingStrategyResolver.resolve(
@@ -6306,7 +6558,7 @@ var Pipeline = class {
6306
6558
  embedBatchOptions
6307
6559
  );
6308
6560
  if (vectors.length !== chunks.length) {
6309
- throw new Error(
6561
+ throw new EmbeddingFailedException(
6310
6562
  `[Pipeline] Embedding mismatch: got ${vectors.length} vectors for ${chunks.length} chunks. Check embedding provider logs for individual chunk failures.`
6311
6563
  );
6312
6564
  }
@@ -6404,11 +6656,11 @@ var Pipeline = class {
6404
6656
  */
6405
6657
  askStream(_0) {
6406
6658
  return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
6407
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
6659
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v;
6408
6660
  yield new __await(this.initialize());
6409
6661
  const ns = namespace != null ? namespace : this.config.projectId;
6410
6662
  const topK = (_b = (_a = this.config.rag) == null ? void 0 : _a.topK) != null ? _b : 5;
6411
- const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0;
6663
+ const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0.3;
6412
6664
  const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
6413
6665
  const requestStart = performance.now();
6414
6666
  try {
@@ -6427,12 +6679,13 @@ var Pipeline = class {
6427
6679
  const embedStart = performance.now();
6428
6680
  const cacheKey = `${ns}::${searchQuery}`;
6429
6681
  const cachedVector = this.embeddingCache.get(cacheKey);
6682
+ const useGraph = this.graphDB && ((_h = this.config.rag) == null ? void 0 : _h.useGraphRetrieval);
6430
6683
  const [strategyResult, embeddedVector] = yield new __await(Promise.all([
6431
6684
  QueryProcessor.determineRetrievalStrategy(
6432
6685
  searchQuery,
6433
- this.llmRouter.get("fast"),
6434
- (_h = this.config.rag) == null ? void 0 : _h.graphKeywords,
6435
- (_i = this.config.rag) == null ? void 0 : _i.vectorKeywords
6686
+ useGraph ? this.llmRouter.get("fast") : void 0,
6687
+ (_i = this.config.rag) == null ? void 0 : _i.graphKeywords,
6688
+ (_j = this.config.rag) == null ? void 0 : _j.vectorKeywords
6436
6689
  ),
6437
6690
  // Embed immediately regardless of strategy — costs nothing if cached.
6438
6691
  // If strategy turns out to be 'graph'-only we just won't use the vector.
@@ -6442,7 +6695,7 @@ var Pipeline = class {
6442
6695
  if (!cachedVector && queryVector.length > 0) {
6443
6696
  this.embeddingCache.set(cacheKey, queryVector);
6444
6697
  }
6445
- const graphData = (strategyResult === "graph" || strategyResult === "both") && this.graphDB && ((_j = this.config.rag) == null ? void 0 : _j.useGraphRetrieval) ? yield new __await(this.graphDB.query(searchQuery)) : void 0;
6698
+ 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;
6446
6699
  const hasMetadataFilter = filter.metadata && Object.keys(filter.metadata).length > 0;
6447
6700
  const hasNumericPredicates = Array.isArray(filter.__numericPredicates) && filter.__numericPredicates.length > 0;
6448
6701
  const wantsExhaustiveList = hasNumericPredicates || hasMetadataFilter || /\b(list|all|show|provide|give|get|browse|find|search|display)\b/i.test(question);
@@ -6455,7 +6708,7 @@ var Pipeline = class {
6455
6708
  const structuredSources = this.applyStructuredFilters(rawSources, filter);
6456
6709
  let fullSources = hasNumericPredicates ? structuredSources : structuredSources.filter((m) => m.score >= scoreThreshold);
6457
6710
  const rerankLimit = wantsExhaustiveList ? retrievalLimit : topK;
6458
- if (!hasNumericPredicates && ((_k = this.config.rag) == null ? void 0 : _k.useReranking)) {
6711
+ if (!hasNumericPredicates && ((_l = this.config.rag) == null ? void 0 : _l.useReranking)) {
6459
6712
  fullSources = yield new __await(this.reranker.rerank(fullSources, question, rerankLimit));
6460
6713
  } else if (!wantsExhaustiveList) {
6461
6714
  fullSources = fullSources.slice(0, topK);
@@ -6486,34 +6739,117 @@ VECTOR CONTEXT:
6486
6739
  ${context}`;
6487
6740
  }
6488
6741
  const allMetadataKeys = Array.from(new Set(sources.flatMap((s) => Object.keys(s.metadata || {}))));
6489
- const trainedSchemaPromise = allMetadataKeys.length > 0 ? SchemaMapper.train(this.llmProvider, ns, allMetadataKeys).catch(() => void 0) : Promise.resolve(void 0);
6490
- const uiTransformationPromise = trainedSchemaPromise.then(
6491
- (trainedSchema) => this.generateUiTransformation(
6742
+ const cachedSchema = allMetadataKeys.length > 0 ? SchemaMapper.getCached(ns, allMetadataKeys) : void 0;
6743
+ if (allMetadataKeys.length > 0 && !cachedSchema) {
6744
+ SchemaMapper.train(this.llmProvider, ns, allMetadataKeys).catch(() => {
6745
+ });
6746
+ }
6747
+ const isProductQ = UITransformer.isProductQueryPublic(question);
6748
+ const uiTransformationPromise = isProductQ ? Promise.resolve(
6749
+ UITransformer.transform(
6492
6750
  question,
6493
6751
  sources,
6494
- trainedSchema,
6495
- hasNumericPredicates
6752
+ this.config,
6753
+ cachedSchema,
6754
+ { visualizationHint: "product_browse", recommendedChart: "text", filterInStockOnly: false, wantsExplicitTable: false, isTemporal: false, isComparison: false, language: "en" }
6496
6755
  )
6756
+ ) : this.generateUiTransformation(
6757
+ question,
6758
+ sources,
6759
+ cachedSchema,
6760
+ hasNumericPredicates
6497
6761
  ).catch((uiError) => {
6498
6762
  console.warn("[Pipeline] UI transformation failed concurrently:", uiError);
6499
- return UITransformer.transform(question, sources, this.config);
6763
+ return UITransformer.transform(question, sources, this.config, cachedSchema);
6500
6764
  });
6765
+ let hallucinationScoringPromise = Promise.resolve(void 0);
6501
6766
  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.)";
6767
+ const isClaude37 = this.config.llm.model.includes("claude-3-7-sonnet");
6768
+ const isNativeThinking = isClaude37 && (((_m = this.config.llm.options) == null ? void 0 : _m.thinking) === true || ((_n = this.config.llm.options) == null ? void 0 : _n.thinking) === "enabled" || ((_o = this.config.llm.options) == null ? void 0 : _o.thinking) !== false);
6769
+ const modelNameLower = this.config.llm.model.toLowerCase();
6770
+ const isReasoningModel = modelNameLower.includes("-r1") || modelNameLower.includes("deepseek-r1") || modelNameLower.includes("reasoning") || modelNameLower.includes("thinking");
6771
+ const isSimulatedThinking = !isNativeThinking && (((_p = this.config.llm.options) == null ? void 0 : _p.thinking) === true || ((_q = this.config.llm.options) == null ? void 0 : _q.thinking) === "enabled" || isReasoningModel && ((_r = this.config.llm.options) == null ? void 0 : _r.thinking) !== false);
6772
+ let finalRestrictionSuffix = restrictionSuffix;
6773
+ if (isSimulatedThinking) {
6774
+ 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.`)";
6775
+ }
6502
6776
  const hardenedHistory = [...history];
6503
- const userQuestion = { role: "user", content: question + restrictionSuffix };
6777
+ const userQuestion = { role: "user", content: question + finalRestrictionSuffix };
6504
6778
  const messages = [...hardenedHistory, userQuestion];
6505
- const systemPrompt = (_l = this.config.llm.systemPrompt) != null ? _l : "";
6779
+ const systemPrompt = (_s = this.config.llm.systemPrompt) != null ? _s : "";
6506
6780
  const userPrompt = messages.map((m) => `${m.role}: ${m.content}`).join("\n");
6507
6781
  let fullReply = "";
6782
+ let thinkingText = "";
6783
+ let thinkingStartMs = performance.now();
6784
+ let thinkingDurationMs = 0;
6508
6785
  const generateStart = performance.now();
6509
6786
  if (this.llmProvider.chatStream) {
6510
6787
  const stream = this.llmProvider.chatStream(messages, context);
6511
6788
  if (!stream) throw new Error(`[Pipeline] ${this.config.llm.provider} chatStream returned undefined`);
6789
+ let inThinking = false;
6790
+ let textBuffer = "";
6512
6791
  try {
6513
6792
  for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
6514
6793
  const chunk = temp.value;
6515
- fullReply += chunk;
6516
- yield chunk;
6794
+ if (chunk.startsWith("\0THINKING\0")) {
6795
+ const thinkingDelta = chunk.slice("\0THINKING\0".length);
6796
+ thinkingText += thinkingDelta;
6797
+ thinkingDurationMs = performance.now() - thinkingStartMs;
6798
+ yield { type: "thinking", text: thinkingDelta };
6799
+ continue;
6800
+ }
6801
+ if (isSimulatedThinking) {
6802
+ textBuffer += chunk;
6803
+ while (textBuffer.length > 0) {
6804
+ if (!inThinking) {
6805
+ const thinkIndex = textBuffer.indexOf("<think>");
6806
+ if (thinkIndex !== -1) {
6807
+ const before = textBuffer.slice(0, thinkIndex);
6808
+ if (before) {
6809
+ fullReply += before;
6810
+ yield before;
6811
+ }
6812
+ inThinking = true;
6813
+ thinkingStartMs = performance.now();
6814
+ textBuffer = textBuffer.slice(thinkIndex + "<think>".length);
6815
+ } else {
6816
+ const maxSafeLength = textBuffer.length - "<think>".length;
6817
+ if (maxSafeLength > 0) {
6818
+ const safeText = textBuffer.slice(0, maxSafeLength);
6819
+ fullReply += safeText;
6820
+ yield safeText;
6821
+ textBuffer = textBuffer.slice(maxSafeLength);
6822
+ }
6823
+ break;
6824
+ }
6825
+ } else {
6826
+ const endThinkIndex = textBuffer.indexOf("</think>");
6827
+ if (endThinkIndex !== -1) {
6828
+ const thinkingDelta = textBuffer.slice(0, endThinkIndex);
6829
+ if (thinkingDelta) {
6830
+ thinkingText += thinkingDelta;
6831
+ thinkingDurationMs = performance.now() - thinkingStartMs;
6832
+ yield { type: "thinking", text: thinkingDelta };
6833
+ }
6834
+ inThinking = false;
6835
+ textBuffer = textBuffer.slice(endThinkIndex + "</think>".length);
6836
+ } else {
6837
+ const maxSafeLength = textBuffer.length - "</think>".length;
6838
+ if (maxSafeLength > 0) {
6839
+ const thinkingDelta = textBuffer.slice(0, maxSafeLength);
6840
+ thinkingText += thinkingDelta;
6841
+ thinkingDurationMs = performance.now() - thinkingStartMs;
6842
+ yield { type: "thinking", text: thinkingDelta };
6843
+ textBuffer = textBuffer.slice(maxSafeLength);
6844
+ }
6845
+ break;
6846
+ }
6847
+ }
6848
+ }
6849
+ } else {
6850
+ fullReply += chunk;
6851
+ yield chunk;
6852
+ }
6517
6853
  }
6518
6854
  } catch (temp) {
6519
6855
  error = [temp];
@@ -6525,17 +6861,42 @@ ${context}`;
6525
6861
  throw error[0];
6526
6862
  }
6527
6863
  }
6864
+ if (isSimulatedThinking && textBuffer.length > 0) {
6865
+ if (inThinking) {
6866
+ thinkingText += textBuffer;
6867
+ yield { type: "thinking", text: textBuffer };
6868
+ } else {
6869
+ fullReply += textBuffer;
6870
+ yield textBuffer;
6871
+ }
6872
+ }
6528
6873
  } else {
6529
6874
  const reply = yield new __await(this.llmProvider.chat(messages, context));
6530
- fullReply = reply;
6531
- yield reply;
6875
+ if (isSimulatedThinking) {
6876
+ const thinkStart = reply.indexOf("<think>");
6877
+ const thinkEnd = reply.indexOf("</think>");
6878
+ if (thinkStart !== -1 && thinkEnd !== -1 && thinkEnd > thinkStart) {
6879
+ thinkingText = reply.slice(thinkStart + "<think>".length, thinkEnd);
6880
+ fullReply = reply.slice(0, thinkStart) + reply.slice(thinkEnd + "</think>".length);
6881
+ thinkingDurationMs = 100;
6882
+ } else {
6883
+ fullReply = reply;
6884
+ }
6885
+ } else {
6886
+ fullReply = reply;
6887
+ }
6888
+ yield fullReply;
6889
+ }
6890
+ const runHallucination = ((_t = this.config.llm.options) == null ? void 0 : _t.hallucinationScoring) === true || this.config.llm.provider !== "ollama" && ((_u = this.config.llm.options) == null ? void 0 : _u.hallucinationScoring) !== false;
6891
+ if (runHallucination) {
6892
+ hallucinationScoringPromise = scoreHallucination(this.llmProvider, fullReply, context).catch(() => void 0);
6532
6893
  }
6533
6894
  const generateMs = performance.now() - generateStart;
6534
6895
  const totalMs = performance.now() - requestStart;
6535
6896
  const latency = {
6536
6897
  embedMs: Math.round(embedMs),
6537
6898
  retrieveMs: Math.round(retrieveMs),
6538
- rerankMs: ((_m = this.config.rag) == null ? void 0 : _m.useReranking) ? Math.round(rerankMs) : void 0,
6899
+ rerankMs: ((_v = this.config.rag) == null ? void 0 : _v.useReranking) ? Math.round(rerankMs) : void 0,
6539
6900
  generateMs: Math.round(generateMs),
6540
6901
  totalMs: Math.round(totalMs)
6541
6902
  };
@@ -6548,12 +6909,16 @@ ${context}`;
6548
6909
  totalTokens: promptTokens + completionTokens,
6549
6910
  estimatedCostUsd: estimateCostUsd(promptTokens, completionTokens, this.config.llm.model)
6550
6911
  };
6551
- const trace = {
6912
+ const [uiTransformation, hallucinationResult] = yield new __await(Promise.all([
6913
+ uiTransformationPromise,
6914
+ hallucinationScoringPromise
6915
+ ]));
6916
+ const trace = __spreadValues({
6552
6917
  requestId,
6553
6918
  query: question,
6554
6919
  rewrittenQuery,
6555
6920
  systemPrompt,
6556
- userPrompt: question + restrictionSuffix,
6921
+ userPrompt: question + finalRestrictionSuffix,
6557
6922
  chunks: sources.map((s) => {
6558
6923
  var _a2;
6559
6924
  return {
@@ -6567,22 +6932,19 @@ ${context}`;
6567
6932
  latency,
6568
6933
  tokens,
6569
6934
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
6570
- };
6571
- const uiTransformation = yield new __await(uiTransformationPromise);
6935
+ }, hallucinationResult ? {
6936
+ hallucinationScore: hallucinationResult.score,
6937
+ hallucinationReason: hallucinationResult.reason
6938
+ } : {});
6572
6939
  yield {
6573
6940
  reply: "",
6574
6941
  sources,
6575
6942
  graphData,
6576
6943
  ui_transformation: uiTransformation,
6577
- trace
6944
+ trace,
6945
+ thinking: thinkingText || void 0,
6946
+ thinkingMs: thinkingDurationMs > 0 ? Math.round(thinkingDurationMs) : void 0
6578
6947
  };
6579
- scoreHallucination(this.llmProvider, fullReply, context).then((hallucinationResult) => {
6580
- if (hallucinationResult) {
6581
- trace.hallucinationScore = hallucinationResult.score;
6582
- trace.hallucinationReason = hallucinationResult.reason;
6583
- }
6584
- }).catch(() => {
6585
- });
6586
6948
  } catch (error2) {
6587
6949
  throw new Error(`[Pipeline] Stream failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
6588
6950
  }
@@ -6592,18 +6954,30 @@ ${context}`;
6592
6954
  * Universal retrieval method combining all enabled providers.
6593
6955
  * Uses an LRU-bounded embedding cache to avoid re-embedding the same query.
6594
6956
  */
6595
- async generateUiTransformation(question, sources, trainedSchema, forceDeterministic = false) {
6957
+ async generateUiTransformation(question, sources, cachedSchema, forceDeterministic = false) {
6958
+ var _a;
6596
6959
  if (!sources || sources.length === 0) {
6597
- return UITransformer.transform(question, sources, this.config, trainedSchema);
6960
+ return UITransformer.transform(question, sources, this.config, cachedSchema);
6961
+ }
6962
+ if (UITransformer.isProductQueryPublic(question)) {
6963
+ return UITransformer.transform(
6964
+ question,
6965
+ sources,
6966
+ this.config,
6967
+ cachedSchema,
6968
+ { visualizationHint: "product_browse", recommendedChart: "text", filterInStockOnly: false, wantsExplicitTable: false, isTemporal: false, isComparison: false, language: "en" }
6969
+ );
6598
6970
  }
6599
- if (forceDeterministic) {
6600
- return UITransformer.transform(question, sources, this.config, trainedSchema);
6971
+ const isLocalProvider = this.config.llm.provider === "ollama";
6972
+ const disableLlmUiTransform = ((_a = this.config.llm.options) == null ? void 0 : _a.disableLlmUiTransform) === true;
6973
+ if (forceDeterministic || isLocalProvider || disableLlmUiTransform) {
6974
+ return UITransformer.transform(question, sources, this.config, cachedSchema);
6601
6975
  }
6602
6976
  try {
6603
6977
  return await UITransformer.analyzeAndDecide(question, sources, this.llmRouter.get("fast"));
6604
6978
  } catch (err) {
6605
6979
  console.warn("[Pipeline] generateUiTransformation failed, using heuristic fallback:", err);
6606
- return UITransformer.transform(question, sources, this.config, trainedSchema);
6980
+ return UITransformer.transform(question, sources, this.config, cachedSchema);
6607
6981
  }
6608
6982
  }
6609
6983
  applyStructuredFilters(sources, filter) {
@@ -6687,25 +7061,29 @@ ${context}`;
6687
7061
  return Number.isFinite(numeric) ? numeric : null;
6688
7062
  }
6689
7063
  async retrieve(query, options) {
6690
- var _a, _b, _c, _d, _e, _f;
7064
+ var _a, _b, _c, _d, _e, _f, _g;
6691
7065
  const ns = (_a = options.namespace) != null ? _a : this.config.projectId;
6692
7066
  const topK = (_b = options.topK) != null ? _b : 5;
6693
7067
  const cacheKey = `${ns}::${query}`;
6694
7068
  let queryVector = this.embeddingCache.get(cacheKey);
6695
- const strategy = await QueryProcessor.determineRetrievalStrategy(query, this.llmRouter.get("fast"));
7069
+ const useGraph = this.graphDB && ((_c = this.config.rag) == null ? void 0 : _c.useGraphRetrieval);
7070
+ const strategy = await QueryProcessor.determineRetrievalStrategy(
7071
+ query,
7072
+ useGraph ? this.llmRouter.get("fast") : void 0
7073
+ );
6696
7074
  console.debug(`[Pipeline] Determined retrieval strategy: ${strategy}`);
6697
7075
  const [retrievedVector, graphData] = await Promise.all([
6698
7076
  // Only embed if we need vector search (strategy is 'vector' or 'both')
6699
7077
  strategy === "vector" || strategy === "both" ? queryVector ? Promise.resolve(queryVector) : this.embeddingProvider.embed(query, { taskType: "query" }) : Promise.resolve([]),
6700
7078
  // Only query graph if we need graph search (strategy is 'graph' or 'both')
6701
- (strategy === "graph" || strategy === "both") && this.graphDB && ((_c = this.config.rag) == null ? void 0 : _c.useGraphRetrieval) ? this.graphDB.query(query) : Promise.resolve(void 0)
7079
+ (strategy === "graph" || strategy === "both") && this.graphDB && ((_d = this.config.rag) == null ? void 0 : _d.useGraphRetrieval) ? this.graphDB.query(query) : Promise.resolve(void 0)
6702
7080
  ]);
6703
7081
  if ((strategy === "vector" || strategy === "both") && !queryVector && retrievedVector && retrievedVector.length > 0) {
6704
7082
  this.embeddingCache.set(cacheKey, retrievedVector);
6705
7083
  queryVector = retrievedVector;
6706
7084
  }
6707
- const baseFilter = __spreadProps(__spreadValues({}, (_d = options.filter) != null ? _d : {}), { queryText: query });
6708
- const numericPredicates = QueryProcessor.extractNumericPredicates(query, (_e = this.config.rag) == null ? void 0 : _e.filterableFields);
7085
+ const baseFilter = __spreadProps(__spreadValues({}, (_e = options.filter) != null ? _e : {}), { queryText: query });
7086
+ const numericPredicates = QueryProcessor.extractNumericPredicates(query, (_f = this.config.rag) == null ? void 0 : _f.filterableFields);
6709
7087
  if (numericPredicates.length > 0) {
6710
7088
  baseFilter.__numericPredicates = numericPredicates;
6711
7089
  }
@@ -6716,7 +7094,7 @@ ${context}`;
6716
7094
  ) : [];
6717
7095
  const resolvedSources = [];
6718
7096
  for (const source of sources) {
6719
- const parentId = (_f = source.metadata) == null ? void 0 : _f.parent_id;
7097
+ const parentId = (_g = source.metadata) == null ? void 0 : _g.parent_id;
6720
7098
  if (parentId) {
6721
7099
  console.log(`[Pipeline] Multi-Vector: Found child chunk. Parent ID: ${parentId}`);
6722
7100
  resolvedSources.push(source);
@@ -6739,10 +7117,13 @@ New Question: ${question}
6739
7117
  Optimized Search Query:`;
6740
7118
  const rewrite = await this.llmProvider.chat(
6741
7119
  [
6742
- { role: "system", content: "You are an assistant that optimizes search queries for RAG systems." },
6743
7120
  { role: "user", content: prompt }
6744
7121
  ],
6745
- ""
7122
+ "",
7123
+ {
7124
+ systemPrompt: "You are an assistant that optimizes search queries for RAG systems. Focus on extracting the core intent and entities. Do not answer the question, just rewrite it.",
7125
+ temperature: 0
7126
+ }
6746
7127
  );
6747
7128
  return rewrite.trim() || question;
6748
7129
  }
@@ -6766,10 +7147,13 @@ ${context}
6766
7147
  Suggestions:`;
6767
7148
  const response = await this.llmProvider.chat(
6768
7149
  [
6769
- { role: "system", content: "You are a helpful assistant that generates search suggestions." },
6770
7150
  { role: "user", content: prompt }
6771
7151
  ],
6772
- ""
7152
+ "",
7153
+ {
7154
+ systemPrompt: "You are a helpful assistant that generates search suggestions based on the provided snippets. Focus on questions that can be answered by the context, keep each under 10 words, and return ONLY a JSON array of strings.",
7155
+ temperature: 0
7156
+ }
6773
7157
  );
6774
7158
  const match = response.match(/\[[\s\S]*\]/);
6775
7159
  if (match) {
@@ -6785,6 +7169,82 @@ Suggestions:`;
6785
7169
  }
6786
7170
  };
6787
7171
 
7172
+ // src/core/Retrivora.ts
7173
+ var Retrivora = class {
7174
+ constructor(config) {
7175
+ this.config = ConfigResolver.resolveUniversal(config);
7176
+ this.pipeline = new Pipeline(this.config);
7177
+ }
7178
+ async initialize() {
7179
+ try {
7180
+ await ConfigValidator.validateAndThrow(this.config);
7181
+ } catch (err) {
7182
+ throw wrapError(err, "CONFIGURATION_ERROR");
7183
+ }
7184
+ try {
7185
+ await this.pipeline.initialize();
7186
+ } catch (err) {
7187
+ throw wrapError(err, "AUTHENTICATION_ERROR");
7188
+ }
7189
+ }
7190
+ async ingest(documents, namespace) {
7191
+ try {
7192
+ return await this.pipeline.ingest(documents, namespace);
7193
+ } catch (err) {
7194
+ const msg = String(err);
7195
+ let defaultCode = "RETRIEVAL_FAILED";
7196
+ if (msg.includes("Embed") || msg.includes("embed")) {
7197
+ defaultCode = "EMBEDDING_FAILED";
7198
+ }
7199
+ throw wrapError(err, defaultCode);
7200
+ }
7201
+ }
7202
+ async ask(question, history = [], namespace) {
7203
+ try {
7204
+ return await this.pipeline.ask(question, history, namespace);
7205
+ } catch (err) {
7206
+ const msg = String(err);
7207
+ let defaultCode = "RETRIEVAL_FAILED";
7208
+ if (msg.includes("Embed") || msg.includes("embed")) {
7209
+ defaultCode = "EMBEDDING_FAILED";
7210
+ }
7211
+ throw wrapError(err, defaultCode);
7212
+ }
7213
+ }
7214
+ askStream(_0) {
7215
+ return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
7216
+ try {
7217
+ const stream = this.pipeline.askStream(question, history, namespace);
7218
+ try {
7219
+ for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
7220
+ const chunk = temp.value;
7221
+ yield chunk;
7222
+ }
7223
+ } catch (temp) {
7224
+ error = [temp];
7225
+ } finally {
7226
+ try {
7227
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
7228
+ } finally {
7229
+ if (error)
7230
+ throw error[0];
7231
+ }
7232
+ }
7233
+ } catch (err) {
7234
+ const msg = String(err);
7235
+ let defaultCode = "RETRIEVAL_FAILED";
7236
+ if (msg.includes("Embed") || msg.includes("embed")) {
7237
+ defaultCode = "EMBEDDING_FAILED";
7238
+ }
7239
+ throw wrapError(err, defaultCode);
7240
+ }
7241
+ });
7242
+ }
7243
+ getPipeline() {
7244
+ return this.pipeline;
7245
+ }
7246
+ };
7247
+
6788
7248
  // src/core/ProviderHealthCheck.ts
6789
7249
  var ProviderHealthCheck = class {
6790
7250
  /**
@@ -6893,6 +7353,8 @@ var VectorPlugin = class {
6893
7353
  constructor(hostConfig) {
6894
7354
  this.config = ConfigResolver.resolve(hostConfig);
6895
7355
  this.validationPromise = ConfigValidator.validateAndThrow(this.config);
7356
+ this.validationPromise.catch(() => {
7357
+ });
6896
7358
  this.pipeline = new Pipeline(this.config);
6897
7359
  }
6898
7360
  /**
@@ -6926,31 +7388,93 @@ var VectorPlugin = class {
6926
7388
  * Run a chat query.
6927
7389
  */
6928
7390
  async chat(message, history = [], namespace) {
6929
- await this.validationPromise;
6930
- return this.pipeline.ask(message, history, namespace);
7391
+ try {
7392
+ await this.validationPromise;
7393
+ } catch (err) {
7394
+ throw wrapError(err, "CONFIGURATION_ERROR");
7395
+ }
7396
+ try {
7397
+ return await this.pipeline.ask(message, history, namespace);
7398
+ } catch (err) {
7399
+ const msg = String(err);
7400
+ let defaultCode = "RETRIEVAL_FAILED";
7401
+ if (msg.includes("Embed") || msg.includes("embed")) {
7402
+ defaultCode = "EMBEDDING_FAILED";
7403
+ }
7404
+ throw wrapError(err, defaultCode);
7405
+ }
6931
7406
  }
6932
7407
  /**
6933
7408
  * Run a streaming chat query.
6934
7409
  */
6935
7410
  chatStream(_0) {
6936
7411
  return __asyncGenerator(this, arguments, function* (message, history = [], namespace) {
6937
- yield new __await(this.validationPromise);
6938
- yield* __yieldStar(this.pipeline.askStream(message, history, namespace));
7412
+ try {
7413
+ yield new __await(this.validationPromise);
7414
+ } catch (err) {
7415
+ throw wrapError(err, "CONFIGURATION_ERROR");
7416
+ }
7417
+ try {
7418
+ const stream = this.pipeline.askStream(message, history, namespace);
7419
+ try {
7420
+ for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
7421
+ const chunk = temp.value;
7422
+ yield chunk;
7423
+ }
7424
+ } catch (temp) {
7425
+ error = [temp];
7426
+ } finally {
7427
+ try {
7428
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
7429
+ } finally {
7430
+ if (error)
7431
+ throw error[0];
7432
+ }
7433
+ }
7434
+ } catch (err) {
7435
+ const msg = String(err);
7436
+ let defaultCode = "RETRIEVAL_FAILED";
7437
+ if (msg.includes("Embed") || msg.includes("embed")) {
7438
+ defaultCode = "EMBEDDING_FAILED";
7439
+ }
7440
+ throw wrapError(err, defaultCode);
7441
+ }
6939
7442
  });
6940
7443
  }
6941
7444
  /**
6942
7445
  * Ingest documents into the vector database.
6943
7446
  */
6944
7447
  async ingest(documents, namespace) {
6945
- await this.validationPromise;
6946
- return this.pipeline.ingest(documents, namespace);
7448
+ try {
7449
+ await this.validationPromise;
7450
+ } catch (err) {
7451
+ throw wrapError(err, "CONFIGURATION_ERROR");
7452
+ }
7453
+ try {
7454
+ return await this.pipeline.ingest(documents, namespace);
7455
+ } catch (err) {
7456
+ const msg = String(err);
7457
+ let defaultCode = "RETRIEVAL_FAILED";
7458
+ if (msg.includes("Embed") || msg.includes("embed")) {
7459
+ defaultCode = "EMBEDDING_FAILED";
7460
+ }
7461
+ throw wrapError(err, defaultCode);
7462
+ }
6947
7463
  }
6948
7464
  /**
6949
7465
  * Get auto-suggestions based on a query prefix.
6950
7466
  */
6951
7467
  async getSuggestions(query, namespace) {
6952
- await this.validationPromise;
6953
- return this.pipeline.getSuggestions(query, namespace);
7468
+ try {
7469
+ await this.validationPromise;
7470
+ } catch (err) {
7471
+ throw wrapError(err, "CONFIGURATION_ERROR");
7472
+ }
7473
+ try {
7474
+ return await this.pipeline.getSuggestions(query, namespace);
7475
+ } catch (err) {
7476
+ throw wrapError(err, "RETRIEVAL_FAILED");
7477
+ }
6954
7478
  }
6955
7479
  };
6956
7480
 
@@ -7322,6 +7846,10 @@ function createStreamHandler(configOrPlugin) {
7322
7846
  if (!isActive) break;
7323
7847
  if (typeof chunk === "string") {
7324
7848
  enqueue(sseTextFrame(chunk));
7849
+ } else if (chunk && typeof chunk === "object" && "type" in chunk && chunk.type === "thinking") {
7850
+ enqueue(`data: ${JSON.stringify(chunk)}
7851
+
7852
+ `);
7325
7853
  } else {
7326
7854
  enqueue(sseMetaFrame(chunk));
7327
7855
  const responseChunk = chunk;
@@ -7493,17 +8021,93 @@ function createUploadHandler(configOrPlugin) {
7493
8021
  }
7494
8022
  };
7495
8023
  }
8024
+ function createSuggestionsHandler(configOrPlugin) {
8025
+ const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
8026
+ return async function POST(req) {
8027
+ try {
8028
+ const body = await req.json();
8029
+ const { query, namespace } = body;
8030
+ if (typeof query !== "string") {
8031
+ return import_server.NextResponse.json({ error: "query is required" }, { status: 400 });
8032
+ }
8033
+ const suggestions = await plugin.getSuggestions(query, namespace);
8034
+ return import_server.NextResponse.json({ suggestions });
8035
+ } catch (err) {
8036
+ const message = err instanceof Error ? err.message : "Internal server error";
8037
+ return import_server.NextResponse.json({ error: message }, { status: 500 });
8038
+ }
8039
+ };
8040
+ }
8041
+ function createRagHandler(configOrPlugin) {
8042
+ const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
8043
+ const chatHandler = createChatHandler(plugin);
8044
+ const streamHandler = createStreamHandler(plugin);
8045
+ const uploadHandler = createUploadHandler(plugin);
8046
+ const healthHandler = createHealthHandler(plugin);
8047
+ const suggestionsHandler = createSuggestionsHandler(plugin);
8048
+ async function routePostRequest(req, segment) {
8049
+ switch (segment) {
8050
+ case "chat":
8051
+ return streamHandler(req);
8052
+ case "chat-sync":
8053
+ return chatHandler(req);
8054
+ case "upload":
8055
+ return uploadHandler(req);
8056
+ case "suggestions":
8057
+ return suggestionsHandler(req);
8058
+ case "health":
8059
+ return healthHandler();
8060
+ default:
8061
+ return import_server.NextResponse.json({ error: `Not Found: POST segment "${segment}" not supported.` }, { status: 404 });
8062
+ }
8063
+ }
8064
+ async function routeGetRequest(req, segment) {
8065
+ if (segment === "health") {
8066
+ return healthHandler();
8067
+ }
8068
+ return import_server.NextResponse.json({ error: `Method Not Allowed: GET is only supported for "health" segment.` }, { status: 405 });
8069
+ }
8070
+ async function getSegment(context) {
8071
+ var _a;
8072
+ const resolvedParams = typeof ((_a = context == null ? void 0 : context.params) == null ? void 0 : _a.then) === "function" ? await context.params : context == null ? void 0 : context.params;
8073
+ const segments = (resolvedParams == null ? void 0 : resolvedParams.retrivora) || [];
8074
+ return segments[0] || "chat";
8075
+ }
8076
+ return {
8077
+ GET: async (req, context) => {
8078
+ try {
8079
+ const segment = await getSegment(context);
8080
+ return await routeGetRequest(req, segment);
8081
+ } catch (err) {
8082
+ const msg = err instanceof Error ? err.message : "GET Routing failed";
8083
+ return import_server.NextResponse.json({ error: msg }, { status: 500 });
8084
+ }
8085
+ },
8086
+ POST: async (req, context) => {
8087
+ try {
8088
+ const segment = await getSegment(context);
8089
+ return await routePostRequest(req, segment);
8090
+ } catch (err) {
8091
+ const msg = err instanceof Error ? err.message : "POST Routing failed";
8092
+ return import_server.NextResponse.json({ error: msg }, { status: 500 });
8093
+ }
8094
+ }
8095
+ };
8096
+ }
7496
8097
  // Annotate the CommonJS export names for ESM import in node:
7497
8098
  0 && (module.exports = {
7498
8099
  AnthropicProvider,
8100
+ AuthenticationException,
7499
8101
  BaseVectorProvider,
7500
8102
  BatchProcessor,
7501
8103
  ChromaDBProvider,
7502
8104
  ConfigBuilder,
7503
8105
  ConfigResolver,
7504
8106
  ConfigValidator,
8107
+ ConfigurationException,
7505
8108
  DocumentChunker,
7506
8109
  DocumentParser,
8110
+ EmbeddingFailedException,
7507
8111
  EmbeddingStrategy,
7508
8112
  EmbeddingStrategyResolver,
7509
8113
  LLMFactory,
@@ -7518,9 +8122,14 @@ function createUploadHandler(configOrPlugin) {
7518
8122
  Pipeline,
7519
8123
  PostgreSQLProvider,
7520
8124
  ProviderHealthCheck,
8125
+ ProviderNotFoundException,
7521
8126
  ProviderRegistry,
7522
8127
  QdrantProvider,
8128
+ RateLimitException,
7523
8129
  RedisProvider,
8130
+ RetrievalException,
8131
+ Retrivora,
8132
+ RetrivoraError,
7524
8133
  UniversalLLMAdapter,
7525
8134
  UniversalVectorProvider,
7526
8135
  VECTOR_PROFILES,
@@ -7530,11 +8139,13 @@ function createUploadHandler(configOrPlugin) {
7530
8139
  createFromPreset,
7531
8140
  createHealthHandler,
7532
8141
  createIngestHandler,
8142
+ createRagHandler,
7533
8143
  createStreamHandler,
7534
8144
  createUploadHandler,
7535
8145
  getRagConfig,
7536
8146
  sseErrorFrame,
7537
8147
  sseFrame,
7538
8148
  sseMetaFrame,
7539
- sseTextFrame
8149
+ sseTextFrame,
8150
+ wrapError
7540
8151
  });