@retrivora-ai/rag-engine 1.0.4 → 1.0.6

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 (40) 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-BjC6zSTV.d.mts} +62 -1
  4. package/dist/{RagConfig-DRJO4hGU.d.ts → RagConfig-BjC6zSTV.d.ts} +62 -1
  5. package/dist/{chunk-6MLZHQZT.mjs → chunk-ZCDJSGUW.mjs} +237 -104
  6. package/dist/handlers/index.d.mts +2 -2
  7. package/dist/handlers/index.d.ts +2 -2
  8. package/dist/handlers/index.js +239 -106
  9. package/dist/handlers/index.mjs +11 -3
  10. package/dist/index-C3bLmWcR.d.ts +206 -0
  11. package/dist/index-CU_fQq__.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 +319 -221
  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/RagConfig.ts +4 -0
  28. package/src/config/uiConstants.ts +23 -0
  29. package/src/core/ConfigResolver.ts +57 -29
  30. package/src/core/LangChainAgent.ts +73 -40
  31. package/src/core/Pipeline.ts +64 -8
  32. package/src/core/ProviderRegistry.ts +2 -2
  33. package/src/core/QueryProcessor.ts +45 -12
  34. package/src/handlers/index.ts +138 -49
  35. package/src/hooks/useRagChat.ts +71 -32
  36. package/src/server.ts +12 -2
  37. package/dist/DocumentChunker-C-sCZPhi.d.mts +0 -102
  38. package/dist/DocumentChunker-C-sCZPhi.d.ts +0 -102
  39. package/dist/index-B2mutkgp.d.ts +0 -116
  40. package/dist/index-Bjy0es5a.d.mts +0 -116
@@ -190,13 +190,23 @@ function getRagConfig(env = process.env) {
190
190
  }
191
191
 
192
192
  // src/core/ConfigResolver.ts
193
+ var _cachedEnvConfig = null;
194
+ function getCachedEnvConfig() {
195
+ if (!_cachedEnvConfig) {
196
+ _cachedEnvConfig = getRagConfig();
197
+ }
198
+ return _cachedEnvConfig;
199
+ }
200
+ function resetConfigCache() {
201
+ _cachedEnvConfig = null;
202
+ }
193
203
  var ConfigResolver = class {
194
204
  /**
195
- * Resolves the final configuration by merging host-provided config with defaults.
205
+ * Resolves the final configuration by merging host-provided config with environment defaults.
196
206
  * @param hostConfig - Partial configuration passed from the host application.
197
207
  */
198
208
  static resolve(hostConfig) {
199
- const envConfig = getRagConfig();
209
+ const envConfig = getCachedEnvConfig();
200
210
  if (!hostConfig) {
201
211
  return envConfig;
202
212
  }
@@ -1508,14 +1518,16 @@ var LangChainAgent = class {
1508
1518
  this.config = config;
1509
1519
  }
1510
1520
  /**
1511
- * Initializes the agent with the RAG pipeline as a primary tool.
1512
- * Dynamically imports LangChain dependencies to avoid build errors if missing.
1521
+ * Initializes the LangChain ReAct agent with the RAG pipeline as a tool.
1522
+ * Dynamically imports langchain so the package doesn't crash if it isn't installed.
1513
1523
  */
1514
1524
  async initialize(chatModel) {
1515
1525
  try {
1516
- const { DynamicTool } = await import(`${"@langchain/core/tools"}`);
1517
- const { ChatPromptTemplate, MessagesPlaceholder } = await import(`${"@langchain/core/prompts"}`);
1518
- const { AgentExecutor, createOpenAIFunctionsAgent } = await import(`${"langchain/agents"}`);
1526
+ const [{ DynamicTool }, { HumanMessage }, { createAgent }] = await Promise.all([
1527
+ import("@langchain/core/tools"),
1528
+ import("@langchain/core/messages"),
1529
+ import("langchain")
1530
+ ]);
1519
1531
  const searchTool = new DynamicTool({
1520
1532
  name: "document_search",
1521
1533
  description: "Use this tool to search through the knowledge base and document repository. Input should be a specific search query.",
@@ -1524,42 +1536,53 @@ var LangChainAgent = class {
1524
1536
  return `Search Results:
1525
1537
  ${response.reply}
1526
1538
 
1527
- Sources Used: ${JSON.stringify(response.sources.map((s) => s.id))}`;
1539
+ Sources Used: ${JSON.stringify(
1540
+ response.sources.map((s) => s.id)
1541
+ )}`;
1528
1542
  }
1529
1543
  });
1530
- const tools = [searchTool];
1531
- const prompt = ChatPromptTemplate.fromMessages([
1532
- ["system", this.config.llm.systemPrompt || "You are a helpful AI assistant with access to a document search tool."],
1533
- new MessagesPlaceholder("chat_history"),
1534
- ["human", "{input}"],
1535
- new MessagesPlaceholder("agent_scratchpad")
1536
- ]);
1537
- const agent = await createOpenAIFunctionsAgent({
1538
- llm: chatModel,
1539
- tools,
1540
- prompt
1541
- });
1542
- this.executor = new AgentExecutor({
1543
- agent,
1544
- tools
1544
+ this.agent = createAgent({
1545
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1546
+ model: chatModel,
1547
+ tools: [searchTool],
1548
+ systemPrompt: this.config.llm.systemPrompt || "You are a helpful AI assistant with access to a document search tool."
1545
1549
  });
1550
+ void HumanMessage;
1546
1551
  } catch (error) {
1547
- console.error("[LangChainAgent] Failed to initialize. Ensure 'langchain' and '@langchain/core' are installed.");
1548
- throw error;
1552
+ const isMissing = error instanceof Error && error.message.includes("Cannot find module");
1553
+ const hint = isMissing ? " Make sure 'langchain' and '@langchain/core' are installed:\n npm install langchain @langchain/core" : "";
1554
+ throw new Error(
1555
+ `[LangChainAgent] Failed to initialize.${hint}
1556
+ ${error instanceof Error ? error.message : String(error)}`
1557
+ );
1549
1558
  }
1550
1559
  }
1551
1560
  /**
1552
1561
  * Run the agentic flow.
1562
+ *
1563
+ * LangChain v1.x: invoke takes `{ messages: [...] }` instead of `{ input, chat_history }`.
1564
+ * The agent returns `{ messages: [...] }` — the last message is the final answer.
1553
1565
  */
1554
1566
  async run(input, chatHistory = []) {
1555
- if (!this.executor) {
1567
+ var _a, _b, _c;
1568
+ if (!this.agent) {
1556
1569
  throw new Error("[LangChainAgent] Agent not initialized. Call initialize() first.");
1557
1570
  }
1558
- const response = await this.executor.invoke({
1559
- input,
1560
- chat_history: chatHistory
1571
+ const { HumanMessage, AIMessage } = await import("@langchain/core/messages");
1572
+ const historyMessages = chatHistory.map(
1573
+ (m) => m.role === "user" ? new HumanMessage(m.content) : new AIMessage(m.content)
1574
+ );
1575
+ const response = await this.agent.invoke({
1576
+ messages: [...historyMessages, new HumanMessage(input)]
1561
1577
  });
1562
- return response.output;
1578
+ const lastMessage = (_a = response == null ? void 0 : response.messages) == null ? void 0 : _a.at(-1);
1579
+ if (lastMessage && typeof lastMessage.content === "string") {
1580
+ return lastMessage.content;
1581
+ }
1582
+ if (Array.isArray(lastMessage == null ? void 0 : lastMessage.content)) {
1583
+ return lastMessage.content.filter((c) => c.type === "text").map((c) => c.text).join("");
1584
+ }
1585
+ return String((_c = (_b = response == null ? void 0 : response.output) != null ? _b : response) != null ? _c : "");
1563
1586
  }
1564
1587
  };
1565
1588
 
@@ -1881,15 +1904,18 @@ var QueryProcessor = class {
1881
1904
  * Checks if a string is likely a question word or common prompt phrase.
1882
1905
  */
1883
1906
  static isLikelyPromptPhrase(value) {
1884
- return /^(what|which|who|where|when|why|how)\b/i.test(value.trim());
1907
+ return /^(what|which|who|where|when|why|how|the|is|are|was|were|in|on|at|by|for|with|about|a|an|to|of)\b/i.test(value.trim());
1885
1908
  }
1886
1909
  /**
1887
1910
  * Scans a natural language question for potential metadata hints and keywords.
1911
+ * @param question The user's query
1912
+ * @param validFields Optional list of known filterable fields to look for
1888
1913
  */
1889
- static extractQueryFieldHints(question) {
1914
+ static extractQueryFieldHints(question, validFields = []) {
1890
1915
  var _a, _b, _c, _d;
1891
1916
  if (!question.trim()) return [];
1892
1917
  const hints = /* @__PURE__ */ new Map();
1918
+ const fieldsToSearch = [.../* @__PURE__ */ new Set([...this.COMMON_METADATA_FIELDS, ...validFields])];
1893
1919
  const addHint = (value, field) => {
1894
1920
  const normalizedValue = this.normalizeHintValue(value);
1895
1921
  if (!normalizedValue) return;
@@ -1920,11 +1946,28 @@ var QueryProcessor = class {
1920
1946
  if (name) addHint(name, "name");
1921
1947
  }
1922
1948
  }
1949
+ if (fieldsToSearch.length > 0) {
1950
+ for (const field of fieldsToSearch) {
1951
+ const forwardPattern = new RegExp(`\\b${field}\\s*(?:is|are|:|of)?\\s+["']?([^"\\n?.!,]{2,60})["']?(?=[?.!,]|$)`, "gi");
1952
+ for (const match of question.matchAll(forwardPattern)) {
1953
+ const value = match[1];
1954
+ if (value && !this.isLikelyPromptPhrase(value)) {
1955
+ addHint(value, field);
1956
+ }
1957
+ }
1958
+ const reversePattern = new RegExp(`\\b([^"\\n?.!,\\s]{2,60})\\s+${field}\\b`, "gi");
1959
+ for (const match of question.matchAll(reversePattern)) {
1960
+ const value = match[1];
1961
+ if (value && !this.isLikelyPromptPhrase(value)) {
1962
+ addHint(value, field);
1963
+ }
1964
+ }
1965
+ }
1966
+ }
1923
1967
  const universalPatterns = [
1924
1968
  { regex: /([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/gi, field: "email", group: 1 },
1925
1969
  { regex: /(\+?\d[\d\-\.\s\(\)]{6,}\d)/g, field: "phone", group: 1 },
1926
1970
  { regex: /(\b\d{4}-\d{2}-\d{2}\b|\b\d{1,2}\/\d{1,2}\/\d{2,4}\b)/g, field: "date", group: 1 },
1927
- { regex: /(\$\s?\d{1,3}(?:,\d{3})*(?:\.\d+)?)/g, field: "amount", group: 1 },
1928
1971
  { regex: /\b(ID|id|identifier)[: ]\s*([A-Za-z0-9\-]{3,})\b/gi, field: "id", group: 2 },
1929
1972
  { regex: /"([^"]{2,120})"/g, group: 1 },
1930
1973
  { regex: /'([^']{2,120})'/g, group: 1 }
@@ -1968,6 +2011,10 @@ var QueryProcessor = class {
1968
2011
  }
1969
2012
  /**
1970
2013
  * Constructs a QueryFilter object from extracted hints.
2014
+ *
2015
+ * Note: proper nouns are extracted inside `extractQueryFieldHints` and surfaced
2016
+ * as field-less hints; `buildQueryFilter` adds them to `keywords` without
2017
+ * re-running the proper noun regex to avoid duplication.
1971
2018
  */
1972
2019
  static buildQueryFilter(question, hints) {
1973
2020
  const filter = { metadata: {}, keywords: [], queryText: question };
@@ -1975,24 +2022,74 @@ var QueryProcessor = class {
1975
2022
  if (hint.field) {
1976
2023
  filter.metadata[hint.field] = hint.value;
1977
2024
  } else {
1978
- filter.keywords.push(hint.value);
2025
+ if (!filter.keywords.includes(hint.value)) {
2026
+ filter.keywords.push(hint.value);
2027
+ }
1979
2028
  }
1980
2029
  }
1981
- for (const match of question.matchAll(/\b[A-Z][a-z]+(?:\s+[A-Z][a-z]+){0,3}\b/g)) {
1982
- const term = this.normalizeHintValue(match[0]);
1983
- if (term && !filter.keywords.includes(term)) filter.keywords.push(term);
1984
- }
1985
2030
  if (Object.keys(filter.metadata || {}).length === 0) delete filter.metadata;
1986
2031
  if (filter.keywords && filter.keywords.length === 0) delete filter.keywords;
1987
2032
  return filter;
1988
2033
  }
1989
2034
  };
2035
+ QueryProcessor.COMMON_METADATA_FIELDS = [
2036
+ "category",
2037
+ "type",
2038
+ "brand",
2039
+ "status",
2040
+ "priority",
2041
+ "id",
2042
+ "name",
2043
+ "email",
2044
+ "phone",
2045
+ "price",
2046
+ "rating",
2047
+ "color",
2048
+ "size",
2049
+ "material",
2050
+ "sku",
2051
+ "role",
2052
+ "department",
2053
+ "location",
2054
+ "tag",
2055
+ "label"
2056
+ ];
1990
2057
 
1991
2058
  // src/core/Pipeline.ts
2059
+ var LRUEmbeddingCache = class {
2060
+ constructor(maxSize = 500) {
2061
+ this.cache = /* @__PURE__ */ new Map();
2062
+ this.maxSize = maxSize;
2063
+ }
2064
+ get(key) {
2065
+ const value = this.cache.get(key);
2066
+ if (value !== void 0) {
2067
+ this.cache.delete(key);
2068
+ this.cache.set(key, value);
2069
+ }
2070
+ return value;
2071
+ }
2072
+ set(key, value) {
2073
+ if (this.cache.has(key)) {
2074
+ this.cache.delete(key);
2075
+ } else if (this.cache.size >= this.maxSize) {
2076
+ const oldestKey = this.cache.keys().next().value;
2077
+ if (oldestKey !== void 0) this.cache.delete(oldestKey);
2078
+ }
2079
+ this.cache.set(key, value);
2080
+ }
2081
+ clear() {
2082
+ this.cache.clear();
2083
+ }
2084
+ get size() {
2085
+ return this.cache.size;
2086
+ }
2087
+ };
1992
2088
  var Pipeline = class {
1993
2089
  constructor(config) {
1994
2090
  this.config = config;
1995
- this.embeddingCache = /* @__PURE__ */ new Map();
2091
+ /** LRU-bounded cache: avoids re-embedding identical queries within the same process. */
2092
+ this.embeddingCache = new LRUEmbeddingCache(500);
1996
2093
  this.initialised = false;
1997
2094
  var _a, _b, _c, _d, _e;
1998
2095
  this.chunker = new DocumentChunker(
@@ -2080,6 +2177,7 @@ var Pipeline = class {
2080
2177
  }
2081
2178
  /**
2082
2179
  * Step 2: Generate embeddings for chunks with retry logic.
2180
+ * Uses batchEmbed when available for efficiency; falls back to sequential embedding.
2083
2181
  */
2084
2182
  async processEmbeddings(chunks) {
2085
2183
  const embedBatchOptions = {
@@ -2093,7 +2191,9 @@ var Pipeline = class {
2093
2191
  embedBatchOptions
2094
2192
  );
2095
2193
  if (vectors.length !== chunks.length) {
2096
- throw new Error(`Embedding mismatch: got ${vectors.length} vectors for ${chunks.length} chunks`);
2194
+ throw new Error(
2195
+ `[Pipeline] Embedding mismatch: got ${vectors.length} vectors for ${chunks.length} chunks. Check embedding provider logs for individual chunk failures.`
2196
+ );
2097
2197
  }
2098
2198
  return vectors;
2099
2199
  }
@@ -2183,7 +2283,7 @@ var Pipeline = class {
2183
2283
  */
2184
2284
  askStream(_0) {
2185
2285
  return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
2186
- var _a, _b, _c, _d, _e, _f;
2286
+ var _a, _b, _c, _d, _e, _f, _g;
2187
2287
  yield new __await(this.initialize());
2188
2288
  const ns = namespace != null ? namespace : this.config.projectId;
2189
2289
  const topK = (_b = (_a = this.config.rag) == null ? void 0 : _a.topK) != null ? _b : 5;
@@ -2193,7 +2293,7 @@ var Pipeline = class {
2193
2293
  if ((_e = this.config.rag) == null ? void 0 : _e.useQueryTransformation) {
2194
2294
  searchQuery = yield new __await(this.rewriteQuery(question, history));
2195
2295
  }
2196
- const hints = QueryProcessor.extractQueryFieldHints(question);
2296
+ const hints = QueryProcessor.extractQueryFieldHints(question, (_f = this.config.rag) == null ? void 0 : _f.filterableFields);
2197
2297
  const filter = QueryProcessor.buildQueryFilter(question, hints);
2198
2298
  const { sources: rawSources, graphData } = yield new __await(this.retrieve(searchQuery, {
2199
2299
  namespace: ns,
@@ -2201,7 +2301,7 @@ var Pipeline = class {
2201
2301
  filter
2202
2302
  }));
2203
2303
  let sources = rawSources.filter((m) => m.score >= scoreThreshold);
2204
- if ((_f = this.config.rag) == null ? void 0 : _f.useReranking) {
2304
+ if ((_g = this.config.rag) == null ? void 0 : _g.useReranking) {
2205
2305
  sources = yield new __await(this.reranker.rerank(sources, question, topK));
2206
2306
  } else {
2207
2307
  sources = sources.slice(0, topK);
@@ -2247,6 +2347,7 @@ ${context}`;
2247
2347
  }
2248
2348
  /**
2249
2349
  * Universal retrieval method combining all enabled providers.
2350
+ * Uses an LRU-bounded embedding cache to avoid re-embedding the same query.
2250
2351
  */
2251
2352
  async retrieve(query, options) {
2252
2353
  var _a, _b, _c;
@@ -2279,10 +2380,13 @@ ${history.map((m) => `${m.role}: ${m.content}`).join("\n")}
2279
2380
  New Question: ${question}
2280
2381
 
2281
2382
  Optimized Search Query:`;
2282
- const rewrite = await this.llmProvider.chat([
2283
- { role: "system", content: "You are an assistant that optimizes search queries for RAG systems." },
2284
- { role: "user", content: prompt }
2285
- ], "");
2383
+ const rewrite = await this.llmProvider.chat(
2384
+ [
2385
+ { role: "system", content: "You are an assistant that optimizes search queries for RAG systems." },
2386
+ { role: "user", content: prompt }
2387
+ ],
2388
+ ""
2389
+ );
2286
2390
  return rewrite.trim() || question;
2287
2391
  }
2288
2392
  };
@@ -2501,8 +2605,35 @@ var DocumentParser = class {
2501
2605
  };
2502
2606
 
2503
2607
  // src/handlers/index.ts
2504
- function createChatHandler(config) {
2505
- const plugin = new VectorPlugin(config);
2608
+ function sseFrame(payload) {
2609
+ return `data: ${JSON.stringify(payload)}
2610
+
2611
+ `;
2612
+ }
2613
+ function sseTextFrame(text) {
2614
+ return `data: ${JSON.stringify({ type: "text", text })}
2615
+
2616
+ `;
2617
+ }
2618
+ function sseMetaFrame(meta) {
2619
+ return `data: ${JSON.stringify(__spreadValues({ type: "metadata" }, meta != null ? meta : {}))}
2620
+
2621
+ `;
2622
+ }
2623
+ function sseErrorFrame(message) {
2624
+ return `data: ${JSON.stringify({ type: "error", error: message })}
2625
+
2626
+ `;
2627
+ }
2628
+ var SSE_HEADERS = {
2629
+ "Content-Type": "text/event-stream; charset=utf-8",
2630
+ "Cache-Control": "no-cache, no-transform",
2631
+ Connection: "keep-alive",
2632
+ "X-Accel-Buffering": "no"
2633
+ // Disable Nginx buffering for streaming
2634
+ };
2635
+ function createChatHandler(configOrPlugin) {
2636
+ const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
2506
2637
  return async function POST(req) {
2507
2638
  try {
2508
2639
  const body = await req.json();
@@ -2518,67 +2649,64 @@ function createChatHandler(config) {
2518
2649
  }
2519
2650
  };
2520
2651
  }
2521
- function createStreamHandler(config) {
2522
- const plugin = new VectorPlugin(config);
2652
+ function createStreamHandler(configOrPlugin) {
2653
+ const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
2523
2654
  return async function POST(req) {
2655
+ let body;
2524
2656
  try {
2525
- const body = await req.json();
2526
- const { message, history = [], namespace } = body;
2527
- const encoder = new TextEncoder();
2528
- const stream = new ReadableStream({
2529
- async start(controller) {
2657
+ body = await req.json();
2658
+ } catch (e) {
2659
+ return new Response(JSON.stringify({ error: "Invalid JSON body" }), {
2660
+ status: 400,
2661
+ headers: { "Content-Type": "application/json" }
2662
+ });
2663
+ }
2664
+ const { message, history = [], namespace } = body;
2665
+ if (!(message == null ? void 0 : message.trim())) {
2666
+ return new Response(JSON.stringify({ error: "message is required" }), {
2667
+ status: 400,
2668
+ headers: { "Content-Type": "application/json" }
2669
+ });
2670
+ }
2671
+ const encoder = new TextEncoder();
2672
+ const stream = new ReadableStream({
2673
+ async start(controller) {
2674
+ const enqueue = (text) => controller.enqueue(encoder.encode(text));
2675
+ try {
2676
+ const pipelineStream = plugin.chatStream(message, history, namespace);
2530
2677
  try {
2531
- const pipelineStream = plugin.chatStream(message, history, namespace);
2532
- try {
2533
- for (var iter = __forAwait(pipelineStream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
2534
- const chunk = temp.value;
2535
- if (typeof chunk === "string") {
2536
- controller.enqueue(encoder.encode(chunk));
2537
- } else {
2538
- controller.enqueue(encoder.encode(`
2539
-
2540
- __METADATA__${JSON.stringify(chunk)}`));
2541
- }
2678
+ for (var iter = __forAwait(pipelineStream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
2679
+ const chunk = temp.value;
2680
+ if (typeof chunk === "string") {
2681
+ enqueue(sseTextFrame(chunk));
2682
+ } else {
2683
+ enqueue(sseMetaFrame(chunk));
2542
2684
  }
2543
- } catch (temp) {
2544
- error = [temp];
2685
+ }
2686
+ } catch (temp) {
2687
+ error = [temp];
2688
+ } finally {
2689
+ try {
2690
+ more && (temp = iter.return) && await temp.call(iter);
2545
2691
  } finally {
2546
- try {
2547
- more && (temp = iter.return) && await temp.call(iter);
2548
- } finally {
2549
- if (error)
2550
- throw error[0];
2551
- }
2692
+ if (error)
2693
+ throw error[0];
2552
2694
  }
2553
- controller.close();
2554
- } catch (streamError) {
2555
- console.error("[createStreamHandler] Stream processing error:", streamError);
2556
- const errorMessage = streamError instanceof Error ? streamError.message : String(streamError);
2557
- controller.enqueue(encoder.encode(`
2558
-
2559
- __ERROR__${JSON.stringify({ error: errorMessage })}`));
2560
- controller.close();
2561
2695
  }
2696
+ } catch (streamError) {
2697
+ const errorMessage = streamError instanceof Error ? streamError.message : String(streamError);
2698
+ console.error("[createStreamHandler] Stream error:", streamError);
2699
+ enqueue(sseErrorFrame(errorMessage));
2700
+ } finally {
2701
+ controller.close();
2562
2702
  }
2563
- });
2564
- return new Response(stream, {
2565
- headers: {
2566
- "Content-Type": "text/event-stream",
2567
- "Cache-Control": "no-cache",
2568
- "Connection": "keep-alive"
2569
- }
2570
- });
2571
- } catch (err) {
2572
- const message = err instanceof Error ? err.message : "Internal server error";
2573
- return new Response(JSON.stringify({ error: message }), {
2574
- status: 500,
2575
- headers: { "Content-Type": "application/json" }
2576
- });
2577
- }
2703
+ }
2704
+ });
2705
+ return new Response(stream, { headers: SSE_HEADERS });
2578
2706
  };
2579
2707
  }
2580
- function createIngestHandler(config) {
2581
- const plugin = new VectorPlugin(config);
2708
+ function createIngestHandler(configOrPlugin) {
2709
+ const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
2582
2710
  return async function POST(req) {
2583
2711
  try {
2584
2712
  const body = await req.json();
@@ -2594,8 +2722,8 @@ function createIngestHandler(config) {
2594
2722
  }
2595
2723
  };
2596
2724
  }
2597
- function createHealthHandler(config) {
2598
- const plugin = new VectorPlugin(config);
2725
+ function createHealthHandler(configOrPlugin) {
2726
+ const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
2599
2727
  return async function GET() {
2600
2728
  try {
2601
2729
  const health = await plugin.checkHealth();
@@ -2611,8 +2739,8 @@ function createHealthHandler(config) {
2611
2739
  }
2612
2740
  };
2613
2741
  }
2614
- function createUploadHandler(config) {
2615
- const plugin = new VectorPlugin(config);
2742
+ function createUploadHandler(configOrPlugin) {
2743
+ const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
2616
2744
  return async function POST(req) {
2617
2745
  try {
2618
2746
  const formData = await req.formData();
@@ -2647,6 +2775,7 @@ function createUploadHandler(config) {
2647
2775
 
2648
2776
  export {
2649
2777
  getRagConfig,
2778
+ resetConfigCache,
2650
2779
  ConfigResolver,
2651
2780
  OpenAIProvider,
2652
2781
  AnthropicProvider,
@@ -2665,6 +2794,10 @@ export {
2665
2794
  ProviderHealthCheck,
2666
2795
  VectorPlugin,
2667
2796
  DocumentParser,
2797
+ sseFrame,
2798
+ sseTextFrame,
2799
+ sseMetaFrame,
2800
+ sseErrorFrame,
2668
2801
  createChatHandler,
2669
2802
  createStreamHandler,
2670
2803
  createIngestHandler,
@@ -1,3 +1,3 @@
1
- import '../RagConfig-DRJO4hGU.mjs';
2
- export { c as createChatHandler, b as createHealthHandler, d as createIngestHandler, f as createStreamHandler, e as createUploadHandler } from '../index-Bjy0es5a.mjs';
1
+ import '../RagConfig-BjC6zSTV.mjs';
2
+ export { c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, j as sseTextFrame } from '../index-CU_fQq__.mjs';
3
3
  import 'next/server';
@@ -1,3 +1,3 @@
1
- import '../RagConfig-DRJO4hGU.js';
2
- export { c as createChatHandler, b as createHealthHandler, d as createIngestHandler, f as createStreamHandler, e as createUploadHandler } from '../index-B2mutkgp.js';
1
+ import '../RagConfig-BjC6zSTV.js';
2
+ export { c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, j as sseTextFrame } from '../index-C3bLmWcR.js';
3
3
  import 'next/server';