@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.
- package/dist/DocumentChunker-Dh9TvmGG.d.mts +45 -0
- package/dist/DocumentChunker-Dh9TvmGG.d.ts +45 -0
- package/dist/{RagConfig-DRJO4hGU.d.mts → RagConfig-BEmz4hVP.d.mts} +58 -1
- package/dist/{RagConfig-DRJO4hGU.d.ts → RagConfig-BEmz4hVP.d.ts} +58 -1
- package/dist/{chunk-6MLZHQZT.mjs → chunk-MWL4AGQI.mjs} +189 -98
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +191 -100
- package/dist/handlers/index.mjs +11 -3
- package/dist/index-CSfaCeux.d.ts +206 -0
- package/dist/index-DFSy0CG6.d.mts +206 -0
- package/dist/index.d.mts +3 -4
- package/dist/index.d.ts +3 -4
- package/dist/index.js +103 -89
- package/dist/index.mjs +91 -95
- package/dist/server.d.mts +45 -97
- package/dist/server.d.ts +45 -97
- package/dist/server.js +271 -215
- package/dist/server.mjs +78 -167
- package/package.json +12 -10
- package/src/components/ChatWindow.tsx +2 -2
- package/src/components/ConfigProvider.tsx +2 -2
- package/src/components/MessageBubble.tsx +2 -2
- package/src/components/SourceCard.tsx +1 -1
- package/src/components/ThemeToggle.tsx +1 -1
- package/src/config/ConfigBuilder.ts +86 -211
- package/src/config/uiConstants.ts +23 -0
- package/src/core/ConfigResolver.ts +57 -29
- package/src/core/LangChainAgent.ts +73 -40
- package/src/core/Pipeline.ts +63 -7
- package/src/core/ProviderRegistry.ts +2 -2
- package/src/core/QueryProcessor.ts +9 -8
- package/src/handlers/index.ts +138 -49
- package/src/hooks/useRagChat.ts +71 -32
- package/src/server.ts +12 -2
- package/dist/DocumentChunker-C-sCZPhi.d.mts +0 -102
- package/dist/DocumentChunker-C-sCZPhi.d.ts +0 -102
- package/dist/index-B2mutkgp.d.ts +0 -116
- package/dist/index-Bjy0es5a.d.mts +0 -116
package/dist/server.js
CHANGED
|
@@ -1551,8 +1551,14 @@ __export(server_exports, {
|
|
|
1551
1551
|
createFromPreset: () => createFromPreset,
|
|
1552
1552
|
createHealthHandler: () => createHealthHandler,
|
|
1553
1553
|
createIngestHandler: () => createIngestHandler,
|
|
1554
|
+
createStreamHandler: () => createStreamHandler,
|
|
1554
1555
|
createUploadHandler: () => createUploadHandler,
|
|
1555
|
-
getRagConfig: () => getRagConfig
|
|
1556
|
+
getRagConfig: () => getRagConfig,
|
|
1557
|
+
resetConfigCache: () => resetConfigCache,
|
|
1558
|
+
sseErrorFrame: () => sseErrorFrame,
|
|
1559
|
+
sseFrame: () => sseFrame,
|
|
1560
|
+
sseMetaFrame: () => sseMetaFrame,
|
|
1561
|
+
sseTextFrame: () => sseTextFrame
|
|
1556
1562
|
});
|
|
1557
1563
|
module.exports = __toCommonJS(server_exports);
|
|
1558
1564
|
|
|
@@ -1734,13 +1740,23 @@ function getRagConfig(env = process.env) {
|
|
|
1734
1740
|
}
|
|
1735
1741
|
|
|
1736
1742
|
// src/core/ConfigResolver.ts
|
|
1743
|
+
var _cachedEnvConfig = null;
|
|
1744
|
+
function getCachedEnvConfig() {
|
|
1745
|
+
if (!_cachedEnvConfig) {
|
|
1746
|
+
_cachedEnvConfig = getRagConfig();
|
|
1747
|
+
}
|
|
1748
|
+
return _cachedEnvConfig;
|
|
1749
|
+
}
|
|
1750
|
+
function resetConfigCache() {
|
|
1751
|
+
_cachedEnvConfig = null;
|
|
1752
|
+
}
|
|
1737
1753
|
var ConfigResolver = class {
|
|
1738
1754
|
/**
|
|
1739
|
-
* Resolves the final configuration by merging host-provided config with defaults.
|
|
1755
|
+
* Resolves the final configuration by merging host-provided config with environment defaults.
|
|
1740
1756
|
* @param hostConfig - Partial configuration passed from the host application.
|
|
1741
1757
|
*/
|
|
1742
1758
|
static resolve(hostConfig) {
|
|
1743
|
-
const envConfig =
|
|
1759
|
+
const envConfig = getCachedEnvConfig();
|
|
1744
1760
|
if (!hostConfig) {
|
|
1745
1761
|
return envConfig;
|
|
1746
1762
|
}
|
|
@@ -3053,14 +3069,16 @@ var LangChainAgent = class {
|
|
|
3053
3069
|
this.config = config;
|
|
3054
3070
|
}
|
|
3055
3071
|
/**
|
|
3056
|
-
* Initializes the agent with the RAG pipeline as a
|
|
3057
|
-
* Dynamically imports
|
|
3072
|
+
* Initializes the LangChain ReAct agent with the RAG pipeline as a tool.
|
|
3073
|
+
* Dynamically imports langchain so the package doesn't crash if it isn't installed.
|
|
3058
3074
|
*/
|
|
3059
3075
|
async initialize(chatModel) {
|
|
3060
3076
|
try {
|
|
3061
|
-
const { DynamicTool } = await
|
|
3062
|
-
|
|
3063
|
-
|
|
3077
|
+
const [{ DynamicTool }, { HumanMessage }, { createAgent }] = await Promise.all([
|
|
3078
|
+
import("@langchain/core/tools"),
|
|
3079
|
+
import("@langchain/core/messages"),
|
|
3080
|
+
import("langchain")
|
|
3081
|
+
]);
|
|
3064
3082
|
const searchTool = new DynamicTool({
|
|
3065
3083
|
name: "document_search",
|
|
3066
3084
|
description: "Use this tool to search through the knowledge base and document repository. Input should be a specific search query.",
|
|
@@ -3069,42 +3087,53 @@ var LangChainAgent = class {
|
|
|
3069
3087
|
return `Search Results:
|
|
3070
3088
|
${response.reply}
|
|
3071
3089
|
|
|
3072
|
-
Sources Used: ${JSON.stringify(
|
|
3090
|
+
Sources Used: ${JSON.stringify(
|
|
3091
|
+
response.sources.map((s) => s.id)
|
|
3092
|
+
)}`;
|
|
3073
3093
|
}
|
|
3074
3094
|
});
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
new MessagesPlaceholder("agent_scratchpad")
|
|
3081
|
-
]);
|
|
3082
|
-
const agent = await createOpenAIFunctionsAgent({
|
|
3083
|
-
llm: chatModel,
|
|
3084
|
-
tools,
|
|
3085
|
-
prompt
|
|
3086
|
-
});
|
|
3087
|
-
this.executor = new AgentExecutor({
|
|
3088
|
-
agent,
|
|
3089
|
-
tools
|
|
3095
|
+
this.agent = createAgent({
|
|
3096
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
3097
|
+
model: chatModel,
|
|
3098
|
+
tools: [searchTool],
|
|
3099
|
+
systemPrompt: this.config.llm.systemPrompt || "You are a helpful AI assistant with access to a document search tool."
|
|
3090
3100
|
});
|
|
3101
|
+
void HumanMessage;
|
|
3091
3102
|
} catch (error) {
|
|
3092
|
-
|
|
3093
|
-
|
|
3103
|
+
const isMissing = error instanceof Error && error.message.includes("Cannot find module");
|
|
3104
|
+
const hint = isMissing ? " Make sure 'langchain' and '@langchain/core' are installed:\n npm install langchain @langchain/core" : "";
|
|
3105
|
+
throw new Error(
|
|
3106
|
+
`[LangChainAgent] Failed to initialize.${hint}
|
|
3107
|
+
${error instanceof Error ? error.message : String(error)}`
|
|
3108
|
+
);
|
|
3094
3109
|
}
|
|
3095
3110
|
}
|
|
3096
3111
|
/**
|
|
3097
3112
|
* Run the agentic flow.
|
|
3113
|
+
*
|
|
3114
|
+
* LangChain v1.x: invoke takes `{ messages: [...] }` instead of `{ input, chat_history }`.
|
|
3115
|
+
* The agent returns `{ messages: [...] }` — the last message is the final answer.
|
|
3098
3116
|
*/
|
|
3099
3117
|
async run(input, chatHistory = []) {
|
|
3100
|
-
|
|
3118
|
+
var _a, _b, _c;
|
|
3119
|
+
if (!this.agent) {
|
|
3101
3120
|
throw new Error("[LangChainAgent] Agent not initialized. Call initialize() first.");
|
|
3102
3121
|
}
|
|
3103
|
-
const
|
|
3104
|
-
|
|
3105
|
-
|
|
3122
|
+
const { HumanMessage, AIMessage } = await import("@langchain/core/messages");
|
|
3123
|
+
const historyMessages = chatHistory.map(
|
|
3124
|
+
(m) => m.role === "user" ? new HumanMessage(m.content) : new AIMessage(m.content)
|
|
3125
|
+
);
|
|
3126
|
+
const response = await this.agent.invoke({
|
|
3127
|
+
messages: [...historyMessages, new HumanMessage(input)]
|
|
3106
3128
|
});
|
|
3107
|
-
|
|
3129
|
+
const lastMessage = (_a = response == null ? void 0 : response.messages) == null ? void 0 : _a.at(-1);
|
|
3130
|
+
if (lastMessage && typeof lastMessage.content === "string") {
|
|
3131
|
+
return lastMessage.content;
|
|
3132
|
+
}
|
|
3133
|
+
if (Array.isArray(lastMessage == null ? void 0 : lastMessage.content)) {
|
|
3134
|
+
return lastMessage.content.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
3135
|
+
}
|
|
3136
|
+
return String((_c = (_b = response == null ? void 0 : response.output) != null ? _b : response) != null ? _c : "");
|
|
3108
3137
|
}
|
|
3109
3138
|
};
|
|
3110
3139
|
|
|
@@ -3513,6 +3542,10 @@ var QueryProcessor = class {
|
|
|
3513
3542
|
}
|
|
3514
3543
|
/**
|
|
3515
3544
|
* Constructs a QueryFilter object from extracted hints.
|
|
3545
|
+
*
|
|
3546
|
+
* Note: proper nouns are extracted inside `extractQueryFieldHints` and surfaced
|
|
3547
|
+
* as field-less hints; `buildQueryFilter` adds them to `keywords` without
|
|
3548
|
+
* re-running the proper noun regex to avoid duplication.
|
|
3516
3549
|
*/
|
|
3517
3550
|
static buildQueryFilter(question, hints) {
|
|
3518
3551
|
const filter = { metadata: {}, keywords: [], queryText: question };
|
|
@@ -3520,13 +3553,11 @@ var QueryProcessor = class {
|
|
|
3520
3553
|
if (hint.field) {
|
|
3521
3554
|
filter.metadata[hint.field] = hint.value;
|
|
3522
3555
|
} else {
|
|
3523
|
-
filter.keywords.
|
|
3556
|
+
if (!filter.keywords.includes(hint.value)) {
|
|
3557
|
+
filter.keywords.push(hint.value);
|
|
3558
|
+
}
|
|
3524
3559
|
}
|
|
3525
3560
|
}
|
|
3526
|
-
for (const match of question.matchAll(/\b[A-Z][a-z]+(?:\s+[A-Z][a-z]+){0,3}\b/g)) {
|
|
3527
|
-
const term = this.normalizeHintValue(match[0]);
|
|
3528
|
-
if (term && !filter.keywords.includes(term)) filter.keywords.push(term);
|
|
3529
|
-
}
|
|
3530
3561
|
if (Object.keys(filter.metadata || {}).length === 0) delete filter.metadata;
|
|
3531
3562
|
if (filter.keywords && filter.keywords.length === 0) delete filter.keywords;
|
|
3532
3563
|
return filter;
|
|
@@ -3534,10 +3565,40 @@ var QueryProcessor = class {
|
|
|
3534
3565
|
};
|
|
3535
3566
|
|
|
3536
3567
|
// src/core/Pipeline.ts
|
|
3568
|
+
var LRUEmbeddingCache = class {
|
|
3569
|
+
constructor(maxSize = 500) {
|
|
3570
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
3571
|
+
this.maxSize = maxSize;
|
|
3572
|
+
}
|
|
3573
|
+
get(key) {
|
|
3574
|
+
const value = this.cache.get(key);
|
|
3575
|
+
if (value !== void 0) {
|
|
3576
|
+
this.cache.delete(key);
|
|
3577
|
+
this.cache.set(key, value);
|
|
3578
|
+
}
|
|
3579
|
+
return value;
|
|
3580
|
+
}
|
|
3581
|
+
set(key, value) {
|
|
3582
|
+
if (this.cache.has(key)) {
|
|
3583
|
+
this.cache.delete(key);
|
|
3584
|
+
} else if (this.cache.size >= this.maxSize) {
|
|
3585
|
+
const oldestKey = this.cache.keys().next().value;
|
|
3586
|
+
if (oldestKey !== void 0) this.cache.delete(oldestKey);
|
|
3587
|
+
}
|
|
3588
|
+
this.cache.set(key, value);
|
|
3589
|
+
}
|
|
3590
|
+
clear() {
|
|
3591
|
+
this.cache.clear();
|
|
3592
|
+
}
|
|
3593
|
+
get size() {
|
|
3594
|
+
return this.cache.size;
|
|
3595
|
+
}
|
|
3596
|
+
};
|
|
3537
3597
|
var Pipeline = class {
|
|
3538
3598
|
constructor(config) {
|
|
3539
3599
|
this.config = config;
|
|
3540
|
-
|
|
3600
|
+
/** LRU-bounded cache: avoids re-embedding identical queries within the same process. */
|
|
3601
|
+
this.embeddingCache = new LRUEmbeddingCache(500);
|
|
3541
3602
|
this.initialised = false;
|
|
3542
3603
|
var _a, _b, _c, _d, _e;
|
|
3543
3604
|
this.chunker = new DocumentChunker(
|
|
@@ -3625,6 +3686,7 @@ var Pipeline = class {
|
|
|
3625
3686
|
}
|
|
3626
3687
|
/**
|
|
3627
3688
|
* Step 2: Generate embeddings for chunks with retry logic.
|
|
3689
|
+
* Uses batchEmbed when available for efficiency; falls back to sequential embedding.
|
|
3628
3690
|
*/
|
|
3629
3691
|
async processEmbeddings(chunks) {
|
|
3630
3692
|
const embedBatchOptions = {
|
|
@@ -3638,7 +3700,9 @@ var Pipeline = class {
|
|
|
3638
3700
|
embedBatchOptions
|
|
3639
3701
|
);
|
|
3640
3702
|
if (vectors.length !== chunks.length) {
|
|
3641
|
-
throw new Error(
|
|
3703
|
+
throw new Error(
|
|
3704
|
+
`[Pipeline] Embedding mismatch: got ${vectors.length} vectors for ${chunks.length} chunks. Check embedding provider logs for individual chunk failures.`
|
|
3705
|
+
);
|
|
3642
3706
|
}
|
|
3643
3707
|
return vectors;
|
|
3644
3708
|
}
|
|
@@ -3792,6 +3856,7 @@ ${context}`;
|
|
|
3792
3856
|
}
|
|
3793
3857
|
/**
|
|
3794
3858
|
* Universal retrieval method combining all enabled providers.
|
|
3859
|
+
* Uses an LRU-bounded embedding cache to avoid re-embedding the same query.
|
|
3795
3860
|
*/
|
|
3796
3861
|
async retrieve(query, options) {
|
|
3797
3862
|
var _a, _b, _c;
|
|
@@ -3824,10 +3889,13 @@ ${history.map((m) => `${m.role}: ${m.content}`).join("\n")}
|
|
|
3824
3889
|
New Question: ${question}
|
|
3825
3890
|
|
|
3826
3891
|
Optimized Search Query:`;
|
|
3827
|
-
const rewrite = await this.llmProvider.chat(
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3892
|
+
const rewrite = await this.llmProvider.chat(
|
|
3893
|
+
[
|
|
3894
|
+
{ role: "system", content: "You are an assistant that optimizes search queries for RAG systems." },
|
|
3895
|
+
{ role: "user", content: prompt }
|
|
3896
|
+
],
|
|
3897
|
+
""
|
|
3898
|
+
);
|
|
3831
3899
|
return rewrite.trim() || question;
|
|
3832
3900
|
}
|
|
3833
3901
|
};
|
|
@@ -3988,21 +4056,11 @@ var VectorPlugin = class {
|
|
|
3988
4056
|
|
|
3989
4057
|
// src/config/ConfigBuilder.ts
|
|
3990
4058
|
var ConfigBuilder = class {
|
|
3991
|
-
constructor() {
|
|
3992
|
-
this.config = {
|
|
3993
|
-
projectId: "default-project",
|
|
3994
|
-
rag: {
|
|
3995
|
-
chunkSize: 1e3,
|
|
3996
|
-
chunkOverlap: 200,
|
|
3997
|
-
topK: 5
|
|
3998
|
-
}
|
|
3999
|
-
};
|
|
4000
|
-
}
|
|
4001
4059
|
/**
|
|
4002
4060
|
* Set the project/application ID for namespacing
|
|
4003
4061
|
*/
|
|
4004
4062
|
projectId(id) {
|
|
4005
|
-
this.
|
|
4063
|
+
this._projectId = id;
|
|
4006
4064
|
return this;
|
|
4007
4065
|
}
|
|
4008
4066
|
/**
|
|
@@ -4011,9 +4069,9 @@ var ConfigBuilder = class {
|
|
|
4011
4069
|
vectorDb(provider, options) {
|
|
4012
4070
|
var _a;
|
|
4013
4071
|
if (provider === "auto") {
|
|
4014
|
-
this.
|
|
4072
|
+
this._vectorDb = this._autoDetectVectorDb();
|
|
4015
4073
|
} else {
|
|
4016
|
-
this.
|
|
4074
|
+
this._vectorDb = {
|
|
4017
4075
|
provider,
|
|
4018
4076
|
indexName: (_a = options == null ? void 0 : options.indexName) != null ? _a : "default",
|
|
4019
4077
|
options: __spreadValues({}, options)
|
|
@@ -4027,9 +4085,9 @@ var ConfigBuilder = class {
|
|
|
4027
4085
|
llm(provider, model, apiKey, options) {
|
|
4028
4086
|
var _a, _b;
|
|
4029
4087
|
if (provider === "auto") {
|
|
4030
|
-
this.
|
|
4088
|
+
this._llm = this._autoDetectLLM();
|
|
4031
4089
|
} else {
|
|
4032
|
-
this.
|
|
4090
|
+
this._llm = {
|
|
4033
4091
|
provider,
|
|
4034
4092
|
model: model != null ? model : "default-model",
|
|
4035
4093
|
apiKey,
|
|
@@ -4047,9 +4105,9 @@ var ConfigBuilder = class {
|
|
|
4047
4105
|
*/
|
|
4048
4106
|
embedding(provider, model, apiKey, options) {
|
|
4049
4107
|
if (provider === "auto") {
|
|
4050
|
-
this.
|
|
4108
|
+
this._embedding = this._autoDetectEmbedding();
|
|
4051
4109
|
} else {
|
|
4052
|
-
this.
|
|
4110
|
+
this._embedding = {
|
|
4053
4111
|
provider,
|
|
4054
4112
|
model: model != null ? model : "default-embedding",
|
|
4055
4113
|
apiKey,
|
|
@@ -4060,26 +4118,46 @@ var ConfigBuilder = class {
|
|
|
4060
4118
|
return this;
|
|
4061
4119
|
}
|
|
4062
4120
|
/**
|
|
4063
|
-
* Set RAG-specific parameters
|
|
4121
|
+
* Set RAG-specific pipeline parameters
|
|
4064
4122
|
*/
|
|
4065
4123
|
rag(options) {
|
|
4066
4124
|
var _a;
|
|
4067
|
-
this.
|
|
4125
|
+
this._rag = __spreadValues(__spreadValues({}, (_a = this._rag) != null ? _a : {}), options);
|
|
4068
4126
|
return this;
|
|
4069
4127
|
}
|
|
4070
4128
|
/**
|
|
4071
|
-
* Set UI
|
|
4129
|
+
* Set UI branding and appearance options.
|
|
4130
|
+
* Accepts the full UIConfig interface.
|
|
4072
4131
|
*/
|
|
4073
4132
|
ui(options) {
|
|
4074
|
-
this.
|
|
4133
|
+
this._ui = options;
|
|
4075
4134
|
return this;
|
|
4076
4135
|
}
|
|
4077
4136
|
/**
|
|
4078
|
-
* Build and return the
|
|
4137
|
+
* Build and return the final RagConfig.
|
|
4138
|
+
* Throws if required fields (projectId, vectorDb, llm, embedding) are not set.
|
|
4079
4139
|
*/
|
|
4080
4140
|
build() {
|
|
4081
|
-
|
|
4082
|
-
|
|
4141
|
+
var _a;
|
|
4142
|
+
const missing = [];
|
|
4143
|
+
if (!this._projectId) missing.push('projectId (call .projectId("my-app"))');
|
|
4144
|
+
if (!this._vectorDb) missing.push('vectorDb (call .vectorDb("pinecone", { ... }))');
|
|
4145
|
+
if (!this._llm) missing.push('llm (call .llm("openai", "gpt-4o", apiKey))');
|
|
4146
|
+
if (!this._embedding) missing.push('embedding (call .embedding("openai", "text-embedding-3-small"))');
|
|
4147
|
+
if (missing.length > 0) {
|
|
4148
|
+
throw new Error(
|
|
4149
|
+
`[ConfigBuilder] Cannot build \u2014 required fields are missing:
|
|
4150
|
+
${missing.join("\n ")}`
|
|
4151
|
+
);
|
|
4152
|
+
}
|
|
4153
|
+
return __spreadValues({
|
|
4154
|
+
projectId: this._projectId,
|
|
4155
|
+
vectorDb: this._vectorDb,
|
|
4156
|
+
llm: this._llm,
|
|
4157
|
+
embedding: this._embedding,
|
|
4158
|
+
ui: this._rag ? this._ui : void 0,
|
|
4159
|
+
rag: (_a = this._rag) != null ? _a : { chunkSize: 1e3, chunkOverlap: 200, topK: 5 }
|
|
4160
|
+
}, this._ui ? { ui: this._ui } : {});
|
|
4083
4161
|
}
|
|
4084
4162
|
/**
|
|
4085
4163
|
* Build and return as JSON for serialization
|
|
@@ -4090,169 +4168,58 @@ var ConfigBuilder = class {
|
|
|
4090
4168
|
// ============================================================================
|
|
4091
4169
|
// Private helper methods for auto-detection
|
|
4092
4170
|
// ============================================================================
|
|
4093
|
-
|
|
4171
|
+
_autoDetectVectorDb() {
|
|
4094
4172
|
if (process.env.PINECONE_API_KEY && process.env.PINECONE_INDEX) {
|
|
4095
|
-
return {
|
|
4096
|
-
provider: "pinecone",
|
|
4097
|
-
indexName: process.env.PINECONE_INDEX,
|
|
4098
|
-
options: { apiKey: process.env.PINECONE_API_KEY }
|
|
4099
|
-
};
|
|
4173
|
+
return { provider: "pinecone", indexName: process.env.PINECONE_INDEX, options: { apiKey: process.env.PINECONE_API_KEY } };
|
|
4100
4174
|
}
|
|
4101
4175
|
if (process.env.QDRANT_URL) {
|
|
4102
|
-
return {
|
|
4103
|
-
provider: "qdrant",
|
|
4104
|
-
indexName: process.env.QDRANT_COLLECTION || "documents",
|
|
4105
|
-
options: {
|
|
4106
|
-
url: process.env.QDRANT_URL,
|
|
4107
|
-
apiKey: process.env.QDRANT_API_KEY
|
|
4108
|
-
}
|
|
4109
|
-
};
|
|
4176
|
+
return { provider: "qdrant", indexName: process.env.QDRANT_COLLECTION || "documents", options: { url: process.env.QDRANT_URL, apiKey: process.env.QDRANT_API_KEY } };
|
|
4110
4177
|
}
|
|
4111
4178
|
if (process.env.DATABASE_URL) {
|
|
4112
|
-
return {
|
|
4113
|
-
provider: "postgresql",
|
|
4114
|
-
indexName: process.env.PG_TABLE || "documents",
|
|
4115
|
-
options: {
|
|
4116
|
-
connectionString: process.env.DATABASE_URL
|
|
4117
|
-
}
|
|
4118
|
-
};
|
|
4179
|
+
return { provider: "postgresql", indexName: process.env.PG_TABLE || "documents", options: { connectionString: process.env.DATABASE_URL } };
|
|
4119
4180
|
}
|
|
4120
4181
|
if (process.env.MONGODB_URI) {
|
|
4121
|
-
return {
|
|
4122
|
-
provider: "mongodb",
|
|
4123
|
-
indexName: process.env.MONGODB_COLLECTION || "documents",
|
|
4124
|
-
options: {
|
|
4125
|
-
uri: process.env.MONGODB_URI,
|
|
4126
|
-
database: process.env.MONGODB_DB || "ai_db",
|
|
4127
|
-
collection: process.env.MONGODB_COLLECTION || "documents"
|
|
4128
|
-
}
|
|
4129
|
-
};
|
|
4182
|
+
return { provider: "mongodb", indexName: process.env.MONGODB_COLLECTION || "documents", options: { uri: process.env.MONGODB_URI, database: process.env.MONGODB_DB || "ai_db", collection: process.env.MONGODB_COLLECTION || "documents" } };
|
|
4130
4183
|
}
|
|
4131
4184
|
if (process.env.REDIS_URL) {
|
|
4132
|
-
return {
|
|
4133
|
-
provider: "redis",
|
|
4134
|
-
indexName: process.env.REDIS_INDEX || "documents",
|
|
4135
|
-
options: {
|
|
4136
|
-
url: process.env.REDIS_URL
|
|
4137
|
-
}
|
|
4138
|
-
};
|
|
4185
|
+
return { provider: "redis", indexName: process.env.REDIS_INDEX || "documents", options: { url: process.env.REDIS_URL } };
|
|
4139
4186
|
}
|
|
4140
|
-
return {
|
|
4141
|
-
provider: "qdrant",
|
|
4142
|
-
indexName: "documents",
|
|
4143
|
-
options: {
|
|
4144
|
-
url: process.env.QDRANT_URL || "http://localhost:6333"
|
|
4145
|
-
}
|
|
4146
|
-
};
|
|
4187
|
+
return { provider: "qdrant", indexName: "documents", options: { url: process.env.QDRANT_URL || "http://localhost:6333" } };
|
|
4147
4188
|
}
|
|
4148
|
-
|
|
4189
|
+
_autoDetectLLM() {
|
|
4149
4190
|
if (process.env.OPENAI_API_KEY) {
|
|
4150
|
-
return {
|
|
4151
|
-
provider: "openai",
|
|
4152
|
-
model: process.env.OPENAI_MODEL || "gpt-4o-mini",
|
|
4153
|
-
apiKey: process.env.OPENAI_API_KEY,
|
|
4154
|
-
maxTokens: parseInt(process.env.OPENAI_MAX_TOKENS || "1024"),
|
|
4155
|
-
temperature: parseFloat(process.env.OPENAI_TEMPERATURE || "0.7")
|
|
4156
|
-
};
|
|
4191
|
+
return { provider: "openai", model: process.env.OPENAI_MODEL || "gpt-4o-mini", apiKey: process.env.OPENAI_API_KEY, maxTokens: parseInt(process.env.OPENAI_MAX_TOKENS || "1024"), temperature: parseFloat(process.env.OPENAI_TEMPERATURE || "0.7") };
|
|
4157
4192
|
}
|
|
4158
4193
|
if (process.env.ANTHROPIC_API_KEY) {
|
|
4159
|
-
return {
|
|
4160
|
-
provider: "anthropic",
|
|
4161
|
-
model: process.env.ANTHROPIC_MODEL || "claude-3-haiku-20240307",
|
|
4162
|
-
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
4163
|
-
maxTokens: parseInt(process.env.ANTHROPIC_MAX_TOKENS || "1024"),
|
|
4164
|
-
temperature: parseFloat(process.env.ANTHROPIC_TEMPERATURE || "0.7")
|
|
4165
|
-
};
|
|
4194
|
+
return { provider: "anthropic", model: process.env.ANTHROPIC_MODEL || "claude-3-haiku-20240307", apiKey: process.env.ANTHROPIC_API_KEY, maxTokens: parseInt(process.env.ANTHROPIC_MAX_TOKENS || "1024"), temperature: parseFloat(process.env.ANTHROPIC_TEMPERATURE || "0.7") };
|
|
4166
4195
|
}
|
|
4167
4196
|
if (process.env.OLLAMA_BASE_URL) {
|
|
4168
|
-
return {
|
|
4169
|
-
provider: "ollama",
|
|
4170
|
-
model: process.env.OLLAMA_MODEL || "mistral",
|
|
4171
|
-
baseUrl: process.env.OLLAMA_BASE_URL,
|
|
4172
|
-
maxTokens: parseInt(process.env.OLLAMA_MAX_TOKENS || "1024"),
|
|
4173
|
-
temperature: parseFloat(process.env.OLLAMA_TEMPERATURE || "0.7")
|
|
4174
|
-
};
|
|
4197
|
+
return { provider: "ollama", model: process.env.OLLAMA_MODEL || "mistral", baseUrl: process.env.OLLAMA_BASE_URL, maxTokens: parseInt(process.env.OLLAMA_MAX_TOKENS || "1024"), temperature: parseFloat(process.env.OLLAMA_TEMPERATURE || "0.7") };
|
|
4175
4198
|
}
|
|
4176
|
-
return {
|
|
4177
|
-
provider: "openai",
|
|
4178
|
-
model: "gpt-4o-mini",
|
|
4179
|
-
apiKey: process.env.OPENAI_API_KEY
|
|
4180
|
-
};
|
|
4199
|
+
return { provider: "openai", model: "gpt-4o-mini", apiKey: process.env.OPENAI_API_KEY };
|
|
4181
4200
|
}
|
|
4182
|
-
|
|
4201
|
+
_autoDetectEmbedding() {
|
|
4183
4202
|
if (process.env.EMBEDDING_PROVIDER) {
|
|
4184
|
-
|
|
4185
|
-
return {
|
|
4186
|
-
provider,
|
|
4187
|
-
model: process.env.EMBEDDING_MODEL || "default",
|
|
4188
|
-
apiKey: process.env.EMBEDDING_API_KEY,
|
|
4189
|
-
baseUrl: process.env.EMBEDDING_BASE_URL
|
|
4190
|
-
};
|
|
4203
|
+
return { provider: process.env.EMBEDDING_PROVIDER, model: process.env.EMBEDDING_MODEL || "default", apiKey: process.env.EMBEDDING_API_KEY, baseUrl: process.env.EMBEDDING_BASE_URL };
|
|
4191
4204
|
}
|
|
4192
|
-
return {
|
|
4193
|
-
provider: "openai",
|
|
4194
|
-
model: "text-embedding-3-small",
|
|
4195
|
-
apiKey: process.env.OPENAI_API_KEY
|
|
4196
|
-
};
|
|
4205
|
+
return { provider: "openai", model: "text-embedding-3-small", apiKey: process.env.OPENAI_API_KEY };
|
|
4197
4206
|
}
|
|
4198
4207
|
};
|
|
4199
4208
|
var PRESETS = {
|
|
4200
|
-
/**
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
"
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
},
|
|
4208
|
-
/**
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
"
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
embedding: "openai"
|
|
4215
|
-
},
|
|
4216
|
-
/**
|
|
4217
|
-
* Local development: Ollama + local Qdrant
|
|
4218
|
-
*/
|
|
4219
|
-
"local-dev": {
|
|
4220
|
-
vectorDb: "qdrant",
|
|
4221
|
-
llm: "ollama",
|
|
4222
|
-
embedding: "ollama"
|
|
4223
|
-
},
|
|
4224
|
-
/**
|
|
4225
|
-
* Fully open-source: Ollama LLM + Qdrant vector DB + Ollama embeddings
|
|
4226
|
-
*/
|
|
4227
|
-
"fully-open-source": {
|
|
4228
|
-
vectorDb: "qdrant",
|
|
4229
|
-
llm: "ollama",
|
|
4230
|
-
embedding: "ollama"
|
|
4231
|
-
},
|
|
4232
|
-
/**
|
|
4233
|
-
* PostgreSQL stack: pgvector + OpenAI
|
|
4234
|
-
*/
|
|
4235
|
-
"postgres-openai": {
|
|
4236
|
-
vectorDb: "postgresql",
|
|
4237
|
-
llm: "openai",
|
|
4238
|
-
embedding: "openai"
|
|
4239
|
-
},
|
|
4240
|
-
/**
|
|
4241
|
-
* Enterprise MongoDB: MongoDB Atlas with OpenAI
|
|
4242
|
-
*/
|
|
4243
|
-
"mongodb-openai": {
|
|
4244
|
-
vectorDb: "mongodb",
|
|
4245
|
-
llm: "openai",
|
|
4246
|
-
embedding: "openai"
|
|
4247
|
-
},
|
|
4248
|
-
/**
|
|
4249
|
-
* Redis stack for caching + search
|
|
4250
|
-
*/
|
|
4251
|
-
"redis-openai": {
|
|
4252
|
-
vectorDb: "redis",
|
|
4253
|
-
llm: "openai",
|
|
4254
|
-
embedding: "openai"
|
|
4255
|
-
}
|
|
4209
|
+
/** OpenAI + Pinecone: Production-ready cloud setup */
|
|
4210
|
+
"openai-pinecone": { vectorDb: "pinecone", llm: "openai", embedding: "openai" },
|
|
4211
|
+
/** Claude + Qdrant: Open-source vector DB + proprietary LLM */
|
|
4212
|
+
"claude-qdrant": { vectorDb: "qdrant", llm: "anthropic", embedding: "openai" },
|
|
4213
|
+
/** Local development: Ollama + local Qdrant */
|
|
4214
|
+
"local-dev": { vectorDb: "qdrant", llm: "ollama", embedding: "ollama" },
|
|
4215
|
+
/** Fully open-source: Ollama LLM + Qdrant + Ollama embeddings */
|
|
4216
|
+
"fully-open-source": { vectorDb: "qdrant", llm: "ollama", embedding: "ollama" },
|
|
4217
|
+
/** PostgreSQL stack: pgvector + OpenAI */
|
|
4218
|
+
"postgres-openai": { vectorDb: "postgresql", llm: "openai", embedding: "openai" },
|
|
4219
|
+
/** Enterprise MongoDB: MongoDB Atlas with OpenAI */
|
|
4220
|
+
"mongodb-openai": { vectorDb: "mongodb", llm: "openai", embedding: "openai" },
|
|
4221
|
+
/** Redis stack for caching + search */
|
|
4222
|
+
"redis-openai": { vectorDb: "redis", llm: "openai", embedding: "openai" }
|
|
4256
4223
|
};
|
|
4257
4224
|
function createFromPreset(presetName) {
|
|
4258
4225
|
const preset = PRESETS[presetName];
|
|
@@ -4531,8 +4498,35 @@ init_UniversalVectorProvider();
|
|
|
4531
4498
|
|
|
4532
4499
|
// src/handlers/index.ts
|
|
4533
4500
|
var import_server = require("next/server");
|
|
4534
|
-
function
|
|
4535
|
-
|
|
4501
|
+
function sseFrame(payload) {
|
|
4502
|
+
return `data: ${JSON.stringify(payload)}
|
|
4503
|
+
|
|
4504
|
+
`;
|
|
4505
|
+
}
|
|
4506
|
+
function sseTextFrame(text) {
|
|
4507
|
+
return `data: ${JSON.stringify({ type: "text", text })}
|
|
4508
|
+
|
|
4509
|
+
`;
|
|
4510
|
+
}
|
|
4511
|
+
function sseMetaFrame(meta) {
|
|
4512
|
+
return `data: ${JSON.stringify(__spreadValues({ type: "metadata" }, meta != null ? meta : {}))}
|
|
4513
|
+
|
|
4514
|
+
`;
|
|
4515
|
+
}
|
|
4516
|
+
function sseErrorFrame(message) {
|
|
4517
|
+
return `data: ${JSON.stringify({ type: "error", error: message })}
|
|
4518
|
+
|
|
4519
|
+
`;
|
|
4520
|
+
}
|
|
4521
|
+
var SSE_HEADERS = {
|
|
4522
|
+
"Content-Type": "text/event-stream; charset=utf-8",
|
|
4523
|
+
"Cache-Control": "no-cache, no-transform",
|
|
4524
|
+
Connection: "keep-alive",
|
|
4525
|
+
"X-Accel-Buffering": "no"
|
|
4526
|
+
// Disable Nginx buffering for streaming
|
|
4527
|
+
};
|
|
4528
|
+
function createChatHandler(configOrPlugin) {
|
|
4529
|
+
const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
|
|
4536
4530
|
return async function POST(req) {
|
|
4537
4531
|
try {
|
|
4538
4532
|
const body = await req.json();
|
|
@@ -4548,8 +4542,64 @@ function createChatHandler(config) {
|
|
|
4548
4542
|
}
|
|
4549
4543
|
};
|
|
4550
4544
|
}
|
|
4551
|
-
function
|
|
4552
|
-
const plugin = new VectorPlugin(
|
|
4545
|
+
function createStreamHandler(configOrPlugin) {
|
|
4546
|
+
const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
|
|
4547
|
+
return async function POST(req) {
|
|
4548
|
+
let body;
|
|
4549
|
+
try {
|
|
4550
|
+
body = await req.json();
|
|
4551
|
+
} catch (e) {
|
|
4552
|
+
return new Response(JSON.stringify({ error: "Invalid JSON body" }), {
|
|
4553
|
+
status: 400,
|
|
4554
|
+
headers: { "Content-Type": "application/json" }
|
|
4555
|
+
});
|
|
4556
|
+
}
|
|
4557
|
+
const { message, history = [], namespace } = body;
|
|
4558
|
+
if (!(message == null ? void 0 : message.trim())) {
|
|
4559
|
+
return new Response(JSON.stringify({ error: "message is required" }), {
|
|
4560
|
+
status: 400,
|
|
4561
|
+
headers: { "Content-Type": "application/json" }
|
|
4562
|
+
});
|
|
4563
|
+
}
|
|
4564
|
+
const encoder = new TextEncoder();
|
|
4565
|
+
const stream = new ReadableStream({
|
|
4566
|
+
async start(controller) {
|
|
4567
|
+
const enqueue = (text) => controller.enqueue(encoder.encode(text));
|
|
4568
|
+
try {
|
|
4569
|
+
const pipelineStream = plugin.chatStream(message, history, namespace);
|
|
4570
|
+
try {
|
|
4571
|
+
for (var iter = __forAwait(pipelineStream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
4572
|
+
const chunk = temp.value;
|
|
4573
|
+
if (typeof chunk === "string") {
|
|
4574
|
+
enqueue(sseTextFrame(chunk));
|
|
4575
|
+
} else {
|
|
4576
|
+
enqueue(sseMetaFrame(chunk));
|
|
4577
|
+
}
|
|
4578
|
+
}
|
|
4579
|
+
} catch (temp) {
|
|
4580
|
+
error = [temp];
|
|
4581
|
+
} finally {
|
|
4582
|
+
try {
|
|
4583
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
4584
|
+
} finally {
|
|
4585
|
+
if (error)
|
|
4586
|
+
throw error[0];
|
|
4587
|
+
}
|
|
4588
|
+
}
|
|
4589
|
+
} catch (streamError) {
|
|
4590
|
+
const errorMessage = streamError instanceof Error ? streamError.message : String(streamError);
|
|
4591
|
+
console.error("[createStreamHandler] Stream error:", streamError);
|
|
4592
|
+
enqueue(sseErrorFrame(errorMessage));
|
|
4593
|
+
} finally {
|
|
4594
|
+
controller.close();
|
|
4595
|
+
}
|
|
4596
|
+
}
|
|
4597
|
+
});
|
|
4598
|
+
return new Response(stream, { headers: SSE_HEADERS });
|
|
4599
|
+
};
|
|
4600
|
+
}
|
|
4601
|
+
function createIngestHandler(configOrPlugin) {
|
|
4602
|
+
const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
|
|
4553
4603
|
return async function POST(req) {
|
|
4554
4604
|
try {
|
|
4555
4605
|
const body = await req.json();
|
|
@@ -4565,8 +4615,8 @@ function createIngestHandler(config) {
|
|
|
4565
4615
|
}
|
|
4566
4616
|
};
|
|
4567
4617
|
}
|
|
4568
|
-
function createHealthHandler(
|
|
4569
|
-
const plugin = new VectorPlugin(
|
|
4618
|
+
function createHealthHandler(configOrPlugin) {
|
|
4619
|
+
const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
|
|
4570
4620
|
return async function GET() {
|
|
4571
4621
|
try {
|
|
4572
4622
|
const health = await plugin.checkHealth();
|
|
@@ -4582,8 +4632,8 @@ function createHealthHandler(config) {
|
|
|
4582
4632
|
}
|
|
4583
4633
|
};
|
|
4584
4634
|
}
|
|
4585
|
-
function createUploadHandler(
|
|
4586
|
-
const plugin = new VectorPlugin(
|
|
4635
|
+
function createUploadHandler(configOrPlugin) {
|
|
4636
|
+
const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
|
|
4587
4637
|
return async function POST(req) {
|
|
4588
4638
|
try {
|
|
4589
4639
|
const formData = await req.formData();
|
|
@@ -4652,6 +4702,12 @@ function createUploadHandler(config) {
|
|
|
4652
4702
|
createFromPreset,
|
|
4653
4703
|
createHealthHandler,
|
|
4654
4704
|
createIngestHandler,
|
|
4705
|
+
createStreamHandler,
|
|
4655
4706
|
createUploadHandler,
|
|
4656
|
-
getRagConfig
|
|
4707
|
+
getRagConfig,
|
|
4708
|
+
resetConfigCache,
|
|
4709
|
+
sseErrorFrame,
|
|
4710
|
+
sseFrame,
|
|
4711
|
+
sseMetaFrame,
|
|
4712
|
+
sseTextFrame
|
|
4657
4713
|
});
|