@retrivora-ai/rag-engine 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/DocumentChunker-Dh9TvmGG.d.mts +45 -0
  2. package/dist/DocumentChunker-Dh9TvmGG.d.ts +45 -0
  3. package/dist/{RagConfig-DRJO4hGU.d.mts → RagConfig-BEmz4hVP.d.mts} +58 -1
  4. package/dist/{RagConfig-DRJO4hGU.d.ts → RagConfig-BEmz4hVP.d.ts} +58 -1
  5. package/dist/{chunk-6MLZHQZT.mjs → chunk-MWL4AGQI.mjs} +189 -98
  6. package/dist/handlers/index.d.mts +2 -2
  7. package/dist/handlers/index.d.ts +2 -2
  8. package/dist/handlers/index.js +191 -100
  9. package/dist/handlers/index.mjs +11 -3
  10. package/dist/index-CSfaCeux.d.ts +206 -0
  11. package/dist/index-DFSy0CG6.d.mts +206 -0
  12. package/dist/index.d.mts +3 -4
  13. package/dist/index.d.ts +3 -4
  14. package/dist/index.js +103 -89
  15. package/dist/index.mjs +91 -95
  16. package/dist/server.d.mts +45 -97
  17. package/dist/server.d.ts +45 -97
  18. package/dist/server.js +271 -215
  19. package/dist/server.mjs +78 -167
  20. package/package.json +12 -10
  21. package/src/components/ChatWindow.tsx +2 -2
  22. package/src/components/ConfigProvider.tsx +2 -2
  23. package/src/components/MessageBubble.tsx +2 -2
  24. package/src/components/SourceCard.tsx +1 -1
  25. package/src/components/ThemeToggle.tsx +1 -1
  26. package/src/config/ConfigBuilder.ts +86 -211
  27. package/src/config/uiConstants.ts +23 -0
  28. package/src/core/ConfigResolver.ts +57 -29
  29. package/src/core/LangChainAgent.ts +73 -40
  30. package/src/core/Pipeline.ts +63 -7
  31. package/src/core/ProviderRegistry.ts +2 -2
  32. package/src/core/QueryProcessor.ts +9 -8
  33. package/src/handlers/index.ts +138 -49
  34. package/src/hooks/useRagChat.ts +71 -32
  35. package/src/server.ts +12 -2
  36. package/dist/DocumentChunker-C-sCZPhi.d.mts +0 -102
  37. package/dist/DocumentChunker-C-sCZPhi.d.ts +0 -102
  38. package/dist/index-B2mutkgp.d.ts +0 -116
  39. package/dist/index-Bjy0es5a.d.mts +0 -116
@@ -1508,7 +1508,11 @@ __export(handlers_exports, {
1508
1508
  createHealthHandler: () => createHealthHandler,
1509
1509
  createIngestHandler: () => createIngestHandler,
1510
1510
  createStreamHandler: () => createStreamHandler,
1511
- createUploadHandler: () => createUploadHandler
1511
+ createUploadHandler: () => createUploadHandler,
1512
+ sseErrorFrame: () => sseErrorFrame,
1513
+ sseFrame: () => sseFrame,
1514
+ sseMetaFrame: () => sseMetaFrame,
1515
+ sseTextFrame: () => sseTextFrame
1512
1516
  });
1513
1517
  module.exports = __toCommonJS(handlers_exports);
1514
1518
  var import_server = require("next/server");
@@ -1691,13 +1695,20 @@ function getRagConfig(env = process.env) {
1691
1695
  }
1692
1696
 
1693
1697
  // src/core/ConfigResolver.ts
1698
+ var _cachedEnvConfig = null;
1699
+ function getCachedEnvConfig() {
1700
+ if (!_cachedEnvConfig) {
1701
+ _cachedEnvConfig = getRagConfig();
1702
+ }
1703
+ return _cachedEnvConfig;
1704
+ }
1694
1705
  var ConfigResolver = class {
1695
1706
  /**
1696
- * Resolves the final configuration by merging host-provided config with defaults.
1707
+ * Resolves the final configuration by merging host-provided config with environment defaults.
1697
1708
  * @param hostConfig - Partial configuration passed from the host application.
1698
1709
  */
1699
1710
  static resolve(hostConfig) {
1700
- const envConfig = getRagConfig();
1711
+ const envConfig = getCachedEnvConfig();
1701
1712
  if (!hostConfig) {
1702
1713
  return envConfig;
1703
1714
  }
@@ -2971,14 +2982,16 @@ var LangChainAgent = class {
2971
2982
  this.config = config;
2972
2983
  }
2973
2984
  /**
2974
- * Initializes the agent with the RAG pipeline as a primary tool.
2975
- * Dynamically imports LangChain dependencies to avoid build errors if missing.
2985
+ * Initializes the LangChain ReAct agent with the RAG pipeline as a tool.
2986
+ * Dynamically imports langchain so the package doesn't crash if it isn't installed.
2976
2987
  */
2977
2988
  async initialize(chatModel) {
2978
2989
  try {
2979
- const { DynamicTool } = await import(`${"@langchain/core/tools"}`);
2980
- const { ChatPromptTemplate, MessagesPlaceholder } = await import(`${"@langchain/core/prompts"}`);
2981
- const { AgentExecutor, createOpenAIFunctionsAgent } = await import(`${"langchain/agents"}`);
2990
+ const [{ DynamicTool }, { HumanMessage }, { createAgent }] = await Promise.all([
2991
+ import("@langchain/core/tools"),
2992
+ import("@langchain/core/messages"),
2993
+ import("langchain")
2994
+ ]);
2982
2995
  const searchTool = new DynamicTool({
2983
2996
  name: "document_search",
2984
2997
  description: "Use this tool to search through the knowledge base and document repository. Input should be a specific search query.",
@@ -2987,42 +3000,53 @@ var LangChainAgent = class {
2987
3000
  return `Search Results:
2988
3001
  ${response.reply}
2989
3002
 
2990
- Sources Used: ${JSON.stringify(response.sources.map((s) => s.id))}`;
3003
+ Sources Used: ${JSON.stringify(
3004
+ response.sources.map((s) => s.id)
3005
+ )}`;
2991
3006
  }
2992
3007
  });
2993
- const tools = [searchTool];
2994
- const prompt = ChatPromptTemplate.fromMessages([
2995
- ["system", this.config.llm.systemPrompt || "You are a helpful AI assistant with access to a document search tool."],
2996
- new MessagesPlaceholder("chat_history"),
2997
- ["human", "{input}"],
2998
- new MessagesPlaceholder("agent_scratchpad")
2999
- ]);
3000
- const agent = await createOpenAIFunctionsAgent({
3001
- llm: chatModel,
3002
- tools,
3003
- prompt
3004
- });
3005
- this.executor = new AgentExecutor({
3006
- agent,
3007
- tools
3008
+ this.agent = createAgent({
3009
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3010
+ model: chatModel,
3011
+ tools: [searchTool],
3012
+ systemPrompt: this.config.llm.systemPrompt || "You are a helpful AI assistant with access to a document search tool."
3008
3013
  });
3014
+ void HumanMessage;
3009
3015
  } catch (error) {
3010
- console.error("[LangChainAgent] Failed to initialize. Ensure 'langchain' and '@langchain/core' are installed.");
3011
- throw error;
3016
+ const isMissing = error instanceof Error && error.message.includes("Cannot find module");
3017
+ const hint = isMissing ? " Make sure 'langchain' and '@langchain/core' are installed:\n npm install langchain @langchain/core" : "";
3018
+ throw new Error(
3019
+ `[LangChainAgent] Failed to initialize.${hint}
3020
+ ${error instanceof Error ? error.message : String(error)}`
3021
+ );
3012
3022
  }
3013
3023
  }
3014
3024
  /**
3015
3025
  * Run the agentic flow.
3026
+ *
3027
+ * LangChain v1.x: invoke takes `{ messages: [...] }` instead of `{ input, chat_history }`.
3028
+ * The agent returns `{ messages: [...] }` — the last message is the final answer.
3016
3029
  */
3017
3030
  async run(input, chatHistory = []) {
3018
- if (!this.executor) {
3031
+ var _a, _b, _c;
3032
+ if (!this.agent) {
3019
3033
  throw new Error("[LangChainAgent] Agent not initialized. Call initialize() first.");
3020
3034
  }
3021
- const response = await this.executor.invoke({
3022
- input,
3023
- chat_history: chatHistory
3035
+ const { HumanMessage, AIMessage } = await import("@langchain/core/messages");
3036
+ const historyMessages = chatHistory.map(
3037
+ (m) => m.role === "user" ? new HumanMessage(m.content) : new AIMessage(m.content)
3038
+ );
3039
+ const response = await this.agent.invoke({
3040
+ messages: [...historyMessages, new HumanMessage(input)]
3024
3041
  });
3025
- return response.output;
3042
+ const lastMessage = (_a = response == null ? void 0 : response.messages) == null ? void 0 : _a.at(-1);
3043
+ if (lastMessage && typeof lastMessage.content === "string") {
3044
+ return lastMessage.content;
3045
+ }
3046
+ if (Array.isArray(lastMessage == null ? void 0 : lastMessage.content)) {
3047
+ return lastMessage.content.filter((c) => c.type === "text").map((c) => c.text).join("");
3048
+ }
3049
+ return String((_c = (_b = response == null ? void 0 : response.output) != null ? _b : response) != null ? _c : "");
3026
3050
  }
3027
3051
  };
3028
3052
 
@@ -3425,6 +3449,10 @@ var QueryProcessor = class {
3425
3449
  }
3426
3450
  /**
3427
3451
  * Constructs a QueryFilter object from extracted hints.
3452
+ *
3453
+ * Note: proper nouns are extracted inside `extractQueryFieldHints` and surfaced
3454
+ * as field-less hints; `buildQueryFilter` adds them to `keywords` without
3455
+ * re-running the proper noun regex to avoid duplication.
3428
3456
  */
3429
3457
  static buildQueryFilter(question, hints) {
3430
3458
  const filter = { metadata: {}, keywords: [], queryText: question };
@@ -3432,13 +3460,11 @@ var QueryProcessor = class {
3432
3460
  if (hint.field) {
3433
3461
  filter.metadata[hint.field] = hint.value;
3434
3462
  } else {
3435
- filter.keywords.push(hint.value);
3463
+ if (!filter.keywords.includes(hint.value)) {
3464
+ filter.keywords.push(hint.value);
3465
+ }
3436
3466
  }
3437
3467
  }
3438
- for (const match of question.matchAll(/\b[A-Z][a-z]+(?:\s+[A-Z][a-z]+){0,3}\b/g)) {
3439
- const term = this.normalizeHintValue(match[0]);
3440
- if (term && !filter.keywords.includes(term)) filter.keywords.push(term);
3441
- }
3442
3468
  if (Object.keys(filter.metadata || {}).length === 0) delete filter.metadata;
3443
3469
  if (filter.keywords && filter.keywords.length === 0) delete filter.keywords;
3444
3470
  return filter;
@@ -3446,10 +3472,40 @@ var QueryProcessor = class {
3446
3472
  };
3447
3473
 
3448
3474
  // src/core/Pipeline.ts
3475
+ var LRUEmbeddingCache = class {
3476
+ constructor(maxSize = 500) {
3477
+ this.cache = /* @__PURE__ */ new Map();
3478
+ this.maxSize = maxSize;
3479
+ }
3480
+ get(key) {
3481
+ const value = this.cache.get(key);
3482
+ if (value !== void 0) {
3483
+ this.cache.delete(key);
3484
+ this.cache.set(key, value);
3485
+ }
3486
+ return value;
3487
+ }
3488
+ set(key, value) {
3489
+ if (this.cache.has(key)) {
3490
+ this.cache.delete(key);
3491
+ } else if (this.cache.size >= this.maxSize) {
3492
+ const oldestKey = this.cache.keys().next().value;
3493
+ if (oldestKey !== void 0) this.cache.delete(oldestKey);
3494
+ }
3495
+ this.cache.set(key, value);
3496
+ }
3497
+ clear() {
3498
+ this.cache.clear();
3499
+ }
3500
+ get size() {
3501
+ return this.cache.size;
3502
+ }
3503
+ };
3449
3504
  var Pipeline = class {
3450
3505
  constructor(config) {
3451
3506
  this.config = config;
3452
- this.embeddingCache = /* @__PURE__ */ new Map();
3507
+ /** LRU-bounded cache: avoids re-embedding identical queries within the same process. */
3508
+ this.embeddingCache = new LRUEmbeddingCache(500);
3453
3509
  this.initialised = false;
3454
3510
  var _a, _b, _c, _d, _e;
3455
3511
  this.chunker = new DocumentChunker(
@@ -3537,6 +3593,7 @@ var Pipeline = class {
3537
3593
  }
3538
3594
  /**
3539
3595
  * Step 2: Generate embeddings for chunks with retry logic.
3596
+ * Uses batchEmbed when available for efficiency; falls back to sequential embedding.
3540
3597
  */
3541
3598
  async processEmbeddings(chunks) {
3542
3599
  const embedBatchOptions = {
@@ -3550,7 +3607,9 @@ var Pipeline = class {
3550
3607
  embedBatchOptions
3551
3608
  );
3552
3609
  if (vectors.length !== chunks.length) {
3553
- throw new Error(`Embedding mismatch: got ${vectors.length} vectors for ${chunks.length} chunks`);
3610
+ throw new Error(
3611
+ `[Pipeline] Embedding mismatch: got ${vectors.length} vectors for ${chunks.length} chunks. Check embedding provider logs for individual chunk failures.`
3612
+ );
3554
3613
  }
3555
3614
  return vectors;
3556
3615
  }
@@ -3704,6 +3763,7 @@ ${context}`;
3704
3763
  }
3705
3764
  /**
3706
3765
  * Universal retrieval method combining all enabled providers.
3766
+ * Uses an LRU-bounded embedding cache to avoid re-embedding the same query.
3707
3767
  */
3708
3768
  async retrieve(query, options) {
3709
3769
  var _a, _b, _c;
@@ -3736,10 +3796,13 @@ ${history.map((m) => `${m.role}: ${m.content}`).join("\n")}
3736
3796
  New Question: ${question}
3737
3797
 
3738
3798
  Optimized Search Query:`;
3739
- const rewrite = await this.llmProvider.chat([
3740
- { role: "system", content: "You are an assistant that optimizes search queries for RAG systems." },
3741
- { role: "user", content: prompt }
3742
- ], "");
3799
+ const rewrite = await this.llmProvider.chat(
3800
+ [
3801
+ { role: "system", content: "You are an assistant that optimizes search queries for RAG systems." },
3802
+ { role: "user", content: prompt }
3803
+ ],
3804
+ ""
3805
+ );
3743
3806
  return rewrite.trim() || question;
3744
3807
  }
3745
3808
  };
@@ -3958,8 +4021,35 @@ var DocumentParser = class {
3958
4021
  };
3959
4022
 
3960
4023
  // src/handlers/index.ts
3961
- function createChatHandler(config) {
3962
- const plugin = new VectorPlugin(config);
4024
+ function sseFrame(payload) {
4025
+ return `data: ${JSON.stringify(payload)}
4026
+
4027
+ `;
4028
+ }
4029
+ function sseTextFrame(text) {
4030
+ return `data: ${JSON.stringify({ type: "text", text })}
4031
+
4032
+ `;
4033
+ }
4034
+ function sseMetaFrame(meta) {
4035
+ return `data: ${JSON.stringify(__spreadValues({ type: "metadata" }, meta != null ? meta : {}))}
4036
+
4037
+ `;
4038
+ }
4039
+ function sseErrorFrame(message) {
4040
+ return `data: ${JSON.stringify({ type: "error", error: message })}
4041
+
4042
+ `;
4043
+ }
4044
+ var SSE_HEADERS = {
4045
+ "Content-Type": "text/event-stream; charset=utf-8",
4046
+ "Cache-Control": "no-cache, no-transform",
4047
+ Connection: "keep-alive",
4048
+ "X-Accel-Buffering": "no"
4049
+ // Disable Nginx buffering for streaming
4050
+ };
4051
+ function createChatHandler(configOrPlugin) {
4052
+ const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
3963
4053
  return async function POST(req) {
3964
4054
  try {
3965
4055
  const body = await req.json();
@@ -3975,67 +4065,64 @@ function createChatHandler(config) {
3975
4065
  }
3976
4066
  };
3977
4067
  }
3978
- function createStreamHandler(config) {
3979
- const plugin = new VectorPlugin(config);
4068
+ function createStreamHandler(configOrPlugin) {
4069
+ const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
3980
4070
  return async function POST(req) {
4071
+ let body;
3981
4072
  try {
3982
- const body = await req.json();
3983
- const { message, history = [], namespace } = body;
3984
- const encoder = new TextEncoder();
3985
- const stream = new ReadableStream({
3986
- async start(controller) {
4073
+ body = await req.json();
4074
+ } catch (e) {
4075
+ return new Response(JSON.stringify({ error: "Invalid JSON body" }), {
4076
+ status: 400,
4077
+ headers: { "Content-Type": "application/json" }
4078
+ });
4079
+ }
4080
+ const { message, history = [], namespace } = body;
4081
+ if (!(message == null ? void 0 : message.trim())) {
4082
+ return new Response(JSON.stringify({ error: "message is required" }), {
4083
+ status: 400,
4084
+ headers: { "Content-Type": "application/json" }
4085
+ });
4086
+ }
4087
+ const encoder = new TextEncoder();
4088
+ const stream = new ReadableStream({
4089
+ async start(controller) {
4090
+ const enqueue = (text) => controller.enqueue(encoder.encode(text));
4091
+ try {
4092
+ const pipelineStream = plugin.chatStream(message, history, namespace);
3987
4093
  try {
3988
- const pipelineStream = plugin.chatStream(message, history, namespace);
3989
- try {
3990
- for (var iter = __forAwait(pipelineStream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
3991
- const chunk = temp.value;
3992
- if (typeof chunk === "string") {
3993
- controller.enqueue(encoder.encode(chunk));
3994
- } else {
3995
- controller.enqueue(encoder.encode(`
3996
-
3997
- __METADATA__${JSON.stringify(chunk)}`));
3998
- }
4094
+ for (var iter = __forAwait(pipelineStream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
4095
+ const chunk = temp.value;
4096
+ if (typeof chunk === "string") {
4097
+ enqueue(sseTextFrame(chunk));
4098
+ } else {
4099
+ enqueue(sseMetaFrame(chunk));
3999
4100
  }
4000
- } catch (temp) {
4001
- error = [temp];
4101
+ }
4102
+ } catch (temp) {
4103
+ error = [temp];
4104
+ } finally {
4105
+ try {
4106
+ more && (temp = iter.return) && await temp.call(iter);
4002
4107
  } finally {
4003
- try {
4004
- more && (temp = iter.return) && await temp.call(iter);
4005
- } finally {
4006
- if (error)
4007
- throw error[0];
4008
- }
4108
+ if (error)
4109
+ throw error[0];
4009
4110
  }
4010
- controller.close();
4011
- } catch (streamError) {
4012
- console.error("[createStreamHandler] Stream processing error:", streamError);
4013
- const errorMessage = streamError instanceof Error ? streamError.message : String(streamError);
4014
- controller.enqueue(encoder.encode(`
4015
-
4016
- __ERROR__${JSON.stringify({ error: errorMessage })}`));
4017
- controller.close();
4018
4111
  }
4112
+ } catch (streamError) {
4113
+ const errorMessage = streamError instanceof Error ? streamError.message : String(streamError);
4114
+ console.error("[createStreamHandler] Stream error:", streamError);
4115
+ enqueue(sseErrorFrame(errorMessage));
4116
+ } finally {
4117
+ controller.close();
4019
4118
  }
4020
- });
4021
- return new Response(stream, {
4022
- headers: {
4023
- "Content-Type": "text/event-stream",
4024
- "Cache-Control": "no-cache",
4025
- "Connection": "keep-alive"
4026
- }
4027
- });
4028
- } catch (err) {
4029
- const message = err instanceof Error ? err.message : "Internal server error";
4030
- return new Response(JSON.stringify({ error: message }), {
4031
- status: 500,
4032
- headers: { "Content-Type": "application/json" }
4033
- });
4034
- }
4119
+ }
4120
+ });
4121
+ return new Response(stream, { headers: SSE_HEADERS });
4035
4122
  };
4036
4123
  }
4037
- function createIngestHandler(config) {
4038
- const plugin = new VectorPlugin(config);
4124
+ function createIngestHandler(configOrPlugin) {
4125
+ const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
4039
4126
  return async function POST(req) {
4040
4127
  try {
4041
4128
  const body = await req.json();
@@ -4051,8 +4138,8 @@ function createIngestHandler(config) {
4051
4138
  }
4052
4139
  };
4053
4140
  }
4054
- function createHealthHandler(config) {
4055
- const plugin = new VectorPlugin(config);
4141
+ function createHealthHandler(configOrPlugin) {
4142
+ const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
4056
4143
  return async function GET() {
4057
4144
  try {
4058
4145
  const health = await plugin.checkHealth();
@@ -4068,8 +4155,8 @@ function createHealthHandler(config) {
4068
4155
  }
4069
4156
  };
4070
4157
  }
4071
- function createUploadHandler(config) {
4072
- const plugin = new VectorPlugin(config);
4158
+ function createUploadHandler(configOrPlugin) {
4159
+ const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
4073
4160
  return async function POST(req) {
4074
4161
  try {
4075
4162
  const formData = await req.formData();
@@ -4107,5 +4194,9 @@ function createUploadHandler(config) {
4107
4194
  createHealthHandler,
4108
4195
  createIngestHandler,
4109
4196
  createStreamHandler,
4110
- createUploadHandler
4197
+ createUploadHandler,
4198
+ sseErrorFrame,
4199
+ sseFrame,
4200
+ sseMetaFrame,
4201
+ sseTextFrame
4111
4202
  });
@@ -3,8 +3,12 @@ import {
3
3
  createHealthHandler,
4
4
  createIngestHandler,
5
5
  createStreamHandler,
6
- createUploadHandler
7
- } from "../chunk-6MLZHQZT.mjs";
6
+ createUploadHandler,
7
+ sseErrorFrame,
8
+ sseFrame,
9
+ sseMetaFrame,
10
+ sseTextFrame
11
+ } from "../chunk-MWL4AGQI.mjs";
8
12
  import "../chunk-YLTMFW4M.mjs";
9
13
  import "../chunk-X4TOT24V.mjs";
10
14
  export {
@@ -12,5 +16,9 @@ export {
12
16
  createHealthHandler,
13
17
  createIngestHandler,
14
18
  createStreamHandler,
15
- createUploadHandler
19
+ createUploadHandler,
20
+ sseErrorFrame,
21
+ sseFrame,
22
+ sseMetaFrame,
23
+ sseTextFrame
16
24
  };
@@ -0,0 +1,206 @@
1
+ import { g as RagConfig, C as ChatMessage, b as ChatResponse, e as IngestDocument } from './RagConfig-BEmz4hVP.js';
2
+ import { NextRequest, NextResponse } from 'next/server';
3
+
4
+ interface ValidationError {
5
+ field: string;
6
+ message: string;
7
+ suggestion?: string;
8
+ severity: 'error' | 'warning';
9
+ }
10
+ /**
11
+ * ConfigValidator.ts — Comprehensive configuration validation.
12
+ * Uses a pluggable architecture to delegate provider-specific checks.
13
+ */
14
+ declare class ConfigValidator {
15
+ /**
16
+ * Validates the entire RagConfig object.
17
+ */
18
+ static validate(config: RagConfig): Promise<ValidationError[]>;
19
+ private static validateVectorDbConfig;
20
+ private static validateLLMConfig;
21
+ private static validateEmbeddingConfig;
22
+ /**
23
+ * Temporary fallbacks for providers not yet migrated to the pluggable architecture.
24
+ */
25
+ private static fallbackVectorValidation;
26
+ private static fallbackLLMValidation;
27
+ private static fallbackEmbeddingValidation;
28
+ private static validateUIConfig;
29
+ private static validateRAGConfig;
30
+ private static isValidCSSColor;
31
+ static validateAndThrow(config: RagConfig): Promise<void>;
32
+ }
33
+
34
+ /**
35
+ * Interface for provider-specific configuration validation logic.
36
+ */
37
+ interface IProviderValidator {
38
+ /**
39
+ * Validates the configuration for a specific provider.
40
+ * @param config - The configuration object to validate.
41
+ * @returns An array of validation errors (empty if valid).
42
+ */
43
+ validate(config: Record<string, unknown>): ValidationError[];
44
+ }
45
+ /**
46
+ * Result of a provider health check.
47
+ */
48
+ interface HealthCheckResult {
49
+ healthy: boolean;
50
+ provider: string;
51
+ version?: string;
52
+ capabilities?: Record<string, unknown>;
53
+ error?: string;
54
+ timestamp: number;
55
+ }
56
+ /**
57
+ * Interface for provider-specific health checking logic.
58
+ */
59
+ interface IProviderHealthChecker {
60
+ /**
61
+ * Performs a health check for a specific provider.
62
+ * @param config - The configuration object used to connect to the provider.
63
+ * @returns A promise that resolves to the health check result.
64
+ */
65
+ check(config: Record<string, unknown>): Promise<HealthCheckResult>;
66
+ }
67
+
68
+ /**
69
+ * VectorPlugin — main orchestrator class.
70
+ * This is the primary interface for host applications.
71
+ *
72
+ * Features:
73
+ * - Configuration resolution from host + environment
74
+ * - Configuration validation with detailed error messages
75
+ * - Provider health checks before initialization
76
+ * - Multi-provider support (Vector DBs & LLMs)
77
+ * - Per-tenant data isolation via namespacing
78
+ */
79
+ declare class VectorPlugin {
80
+ private config;
81
+ private pipeline;
82
+ private validationPromise;
83
+ constructor(hostConfig?: Partial<RagConfig>);
84
+ /**
85
+ * Get the current resolved configuration.
86
+ */
87
+ getConfig(): RagConfig;
88
+ /**
89
+ * Perform pre-flight health checks on all configured providers.
90
+ * Useful to verify connectivity before running operations.
91
+ *
92
+ * @returns Health status for vector DB, LLM, and embedding providers
93
+ */
94
+ checkHealth(): Promise<{
95
+ vectorDb: HealthCheckResult;
96
+ llm: HealthCheckResult;
97
+ embedding?: HealthCheckResult;
98
+ allHealthy: boolean;
99
+ }>;
100
+ /**
101
+ * Run a chat query.
102
+ */
103
+ chat(message: string, history?: ChatMessage[], namespace?: string): Promise<ChatResponse>;
104
+ /**
105
+ * Run a streaming chat query.
106
+ */
107
+ chatStream(message: string, history?: ChatMessage[], namespace?: string): AsyncGenerator<string | ChatResponse, void, any>;
108
+ /**
109
+ * Ingest documents into the vector database.
110
+ */
111
+ ingest(documents: IngestDocument[], namespace?: string): Promise<Array<{
112
+ docId: string | number;
113
+ chunksIngested: number;
114
+ }>>;
115
+ }
116
+
117
+ /**
118
+ * Encode a payload as a Server-Sent Events frame.
119
+ * data: <json>\n\n
120
+ */
121
+ declare function sseFrame(payload: unknown): string;
122
+ /** Encode a plain text chunk as an SSE frame. */
123
+ declare function sseTextFrame(text: string): string;
124
+ /** Encode the retrieval metadata as an SSE frame. */
125
+ declare function sseMetaFrame(meta: unknown): string;
126
+ /** Encode a stream error as an SSE frame. */
127
+ declare function sseErrorFrame(message: string): string;
128
+ /**
129
+ * createChatHandler — factory that returns a Next.js App Router POST handler.
130
+ *
131
+ * Accepts either a full/partial `RagConfig` **or** a pre-built `VectorPlugin`
132
+ * instance (preferred for singleton/multi-tenant setups).
133
+ *
134
+ * @example
135
+ * // Option A — pass config (plugin created once at module load time)
136
+ * export const POST = createChatHandler(getRagConfig());
137
+ *
138
+ * // Option B — pass a pre-built plugin (most flexible)
139
+ * const plugin = new VectorPlugin(getRagConfig());
140
+ * export const POST = createChatHandler(plugin);
141
+ */
142
+ declare function createChatHandler(configOrPlugin?: Partial<RagConfig> | VectorPlugin): (req: NextRequest) => Promise<NextResponse<{
143
+ error: string;
144
+ }> | NextResponse<ChatResponse>>;
145
+ /**
146
+ * createStreamHandler — factory for a streaming SSE Next.js App Router POST handler.
147
+ *
148
+ * Streams the assistant response as Server-Sent Events (SSE). Each frame is a
149
+ * JSON object with a `type` discriminant:
150
+ * - `{ type: "text", text: "..." }` — incremental text chunk
151
+ * - `{ type: "metadata", sources: [...] }` — retrieval metadata (last frame)
152
+ * - `{ type: "error", error: "..." }` — stream-level error
153
+ *
154
+ * @example
155
+ * // src/app/api/chat/route.ts
156
+ * export const POST = createStreamHandler(getRagConfig());
157
+ *
158
+ * // Client-side parsing in useRagChat.ts:
159
+ * // const lines = chunk.split('\n');
160
+ * // for (const line of lines) {
161
+ * // if (line.startsWith('data: ')) {
162
+ * // const frame = JSON.parse(line.slice(6));
163
+ * // if (frame.type === 'text') { ... }
164
+ * // }
165
+ * // }
166
+ */
167
+ declare function createStreamHandler(configOrPlugin?: Partial<RagConfig> | VectorPlugin): (req: NextRequest) => Promise<Response>;
168
+ /**
169
+ * createIngestHandler — factory for the document ingestion endpoint.
170
+ */
171
+ declare function createIngestHandler(configOrPlugin?: Partial<RagConfig> | VectorPlugin): (req: NextRequest) => Promise<NextResponse<{
172
+ error: string;
173
+ }> | NextResponse<{
174
+ results: {
175
+ docId: string | number;
176
+ chunksIngested: number;
177
+ }[];
178
+ }>>;
179
+ /**
180
+ * createHealthHandler — factory for the health-check endpoint.
181
+ */
182
+ declare function createHealthHandler(configOrPlugin?: Partial<RagConfig> | VectorPlugin): () => Promise<NextResponse<{
183
+ timestamp: string;
184
+ vectorDb: HealthCheckResult;
185
+ llm: HealthCheckResult;
186
+ embedding?: HealthCheckResult;
187
+ allHealthy: boolean;
188
+ status: string;
189
+ }> | NextResponse<{
190
+ status: string;
191
+ error: string;
192
+ }>>;
193
+ /**
194
+ * createUploadHandler — factory for the file upload ingestion endpoint.
195
+ */
196
+ declare function createUploadHandler(configOrPlugin?: Partial<RagConfig> | VectorPlugin): (req: NextRequest) => Promise<NextResponse<{
197
+ error: string;
198
+ }> | NextResponse<{
199
+ message: string;
200
+ results: {
201
+ docId: string | number;
202
+ chunksIngested: number;
203
+ }[];
204
+ }>>;
205
+
206
+ export { ConfigValidator as C, type HealthCheckResult as H, type IProviderValidator as I, type ValidationError as V, type IProviderHealthChecker as a, VectorPlugin as b, createChatHandler as c, createHealthHandler as d, createIngestHandler as e, createStreamHandler as f, createUploadHandler as g, sseFrame as h, sseMetaFrame as i, sseTextFrame as j, sseErrorFrame as s };