@retrivora-ai/rag-engine 1.0.3 → 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-3JR3SAWX.mjs → chunk-MWL4AGQI.mjs} +216 -108
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +218 -110
- 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 +298 -225
- 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/rag/EntityExtractor.ts +40 -13
- 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
|
}
|
|
@@ -2953,25 +2969,42 @@ Text to extract from:
|
|
|
2953
2969
|
const response = await this.llm.chat([
|
|
2954
2970
|
{ role: "system", content: "You are a precise knowledge graph extraction engine. You always output valid JSON and nothing else." },
|
|
2955
2971
|
{ role: "user", content: prompt }
|
|
2956
|
-
], "", { maxTokens:
|
|
2972
|
+
], "", { maxTokens: 4096, temperature: 0.1 });
|
|
2957
2973
|
try {
|
|
2958
2974
|
const jsonMatch = response.match(/\{[\s\S]*\}/);
|
|
2959
2975
|
const cleanJson = jsonMatch ? jsonMatch[0] : response.trim();
|
|
2960
2976
|
return JSON.parse(cleanJson);
|
|
2961
2977
|
} catch (e) {
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
const jsonMatch = partialResponse.match(/\{[\s\S]*\}/);
|
|
2967
|
-
if (jsonMatch) return JSON.parse(jsonMatch[0]);
|
|
2968
|
-
} catch (e2) {
|
|
2969
|
-
}
|
|
2978
|
+
try {
|
|
2979
|
+
const repaired = this.repairTruncatedJson(response);
|
|
2980
|
+
if (repaired) return JSON.parse(repaired);
|
|
2981
|
+
} catch (e2) {
|
|
2970
2982
|
}
|
|
2971
|
-
console.warn(
|
|
2983
|
+
console.warn(`[EntityExtractor] Failed to parse LLM response. Length: ${response.length} chars.`);
|
|
2984
|
+
console.warn("[EntityExtractor] Snippet:", response.substring(0, 100) + "...");
|
|
2972
2985
|
return { nodes: [], edges: [] };
|
|
2973
2986
|
}
|
|
2974
2987
|
}
|
|
2988
|
+
/**
|
|
2989
|
+
* Attempts to fix JSON that was cut off mid-generation.
|
|
2990
|
+
* Strategy: Find the last valid element in an array and close the structure.
|
|
2991
|
+
*/
|
|
2992
|
+
repairTruncatedJson(json) {
|
|
2993
|
+
let text = json.trim();
|
|
2994
|
+
const startIdx = text.indexOf("{");
|
|
2995
|
+
if (startIdx === -1) return null;
|
|
2996
|
+
text = text.substring(startIdx);
|
|
2997
|
+
const lastCompleteObjectIdx = text.lastIndexOf("}");
|
|
2998
|
+
if (lastCompleteObjectIdx === -1) return null;
|
|
2999
|
+
let repaired = text.substring(0, lastCompleteObjectIdx + 1);
|
|
3000
|
+
const openBrackets = (repaired.match(/\{/g) || []).length;
|
|
3001
|
+
const closedBrackets = (repaired.match(/\}/g) || []).length;
|
|
3002
|
+
const openSquares = (repaired.match(/\[/g) || []).length;
|
|
3003
|
+
const closedSquares = (repaired.match(/\]/g) || []).length;
|
|
3004
|
+
for (let i = 0; i < openSquares - closedSquares; i++) repaired += "]";
|
|
3005
|
+
for (let i = 0; i < openBrackets - closedBrackets; i++) repaired += "}";
|
|
3006
|
+
return repaired;
|
|
3007
|
+
}
|
|
2975
3008
|
};
|
|
2976
3009
|
|
|
2977
3010
|
// src/rag/Reranker.ts
|
|
@@ -3036,14 +3069,16 @@ var LangChainAgent = class {
|
|
|
3036
3069
|
this.config = config;
|
|
3037
3070
|
}
|
|
3038
3071
|
/**
|
|
3039
|
-
* Initializes the agent with the RAG pipeline as a
|
|
3040
|
-
* 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.
|
|
3041
3074
|
*/
|
|
3042
3075
|
async initialize(chatModel) {
|
|
3043
3076
|
try {
|
|
3044
|
-
const { DynamicTool } = await
|
|
3045
|
-
|
|
3046
|
-
|
|
3077
|
+
const [{ DynamicTool }, { HumanMessage }, { createAgent }] = await Promise.all([
|
|
3078
|
+
import("@langchain/core/tools"),
|
|
3079
|
+
import("@langchain/core/messages"),
|
|
3080
|
+
import("langchain")
|
|
3081
|
+
]);
|
|
3047
3082
|
const searchTool = new DynamicTool({
|
|
3048
3083
|
name: "document_search",
|
|
3049
3084
|
description: "Use this tool to search through the knowledge base and document repository. Input should be a specific search query.",
|
|
@@ -3052,42 +3087,53 @@ var LangChainAgent = class {
|
|
|
3052
3087
|
return `Search Results:
|
|
3053
3088
|
${response.reply}
|
|
3054
3089
|
|
|
3055
|
-
Sources Used: ${JSON.stringify(
|
|
3090
|
+
Sources Used: ${JSON.stringify(
|
|
3091
|
+
response.sources.map((s) => s.id)
|
|
3092
|
+
)}`;
|
|
3056
3093
|
}
|
|
3057
3094
|
});
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
new MessagesPlaceholder("agent_scratchpad")
|
|
3064
|
-
]);
|
|
3065
|
-
const agent = await createOpenAIFunctionsAgent({
|
|
3066
|
-
llm: chatModel,
|
|
3067
|
-
tools,
|
|
3068
|
-
prompt
|
|
3069
|
-
});
|
|
3070
|
-
this.executor = new AgentExecutor({
|
|
3071
|
-
agent,
|
|
3072
|
-
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."
|
|
3073
3100
|
});
|
|
3101
|
+
void HumanMessage;
|
|
3074
3102
|
} catch (error) {
|
|
3075
|
-
|
|
3076
|
-
|
|
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
|
+
);
|
|
3077
3109
|
}
|
|
3078
3110
|
}
|
|
3079
3111
|
/**
|
|
3080
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.
|
|
3081
3116
|
*/
|
|
3082
3117
|
async run(input, chatHistory = []) {
|
|
3083
|
-
|
|
3118
|
+
var _a, _b, _c;
|
|
3119
|
+
if (!this.agent) {
|
|
3084
3120
|
throw new Error("[LangChainAgent] Agent not initialized. Call initialize() first.");
|
|
3085
3121
|
}
|
|
3086
|
-
const
|
|
3087
|
-
|
|
3088
|
-
|
|
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)]
|
|
3089
3128
|
});
|
|
3090
|
-
|
|
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 : "");
|
|
3091
3137
|
}
|
|
3092
3138
|
};
|
|
3093
3139
|
|
|
@@ -3496,6 +3542,10 @@ var QueryProcessor = class {
|
|
|
3496
3542
|
}
|
|
3497
3543
|
/**
|
|
3498
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.
|
|
3499
3549
|
*/
|
|
3500
3550
|
static buildQueryFilter(question, hints) {
|
|
3501
3551
|
const filter = { metadata: {}, keywords: [], queryText: question };
|
|
@@ -3503,13 +3553,11 @@ var QueryProcessor = class {
|
|
|
3503
3553
|
if (hint.field) {
|
|
3504
3554
|
filter.metadata[hint.field] = hint.value;
|
|
3505
3555
|
} else {
|
|
3506
|
-
filter.keywords.
|
|
3556
|
+
if (!filter.keywords.includes(hint.value)) {
|
|
3557
|
+
filter.keywords.push(hint.value);
|
|
3558
|
+
}
|
|
3507
3559
|
}
|
|
3508
3560
|
}
|
|
3509
|
-
for (const match of question.matchAll(/\b[A-Z][a-z]+(?:\s+[A-Z][a-z]+){0,3}\b/g)) {
|
|
3510
|
-
const term = this.normalizeHintValue(match[0]);
|
|
3511
|
-
if (term && !filter.keywords.includes(term)) filter.keywords.push(term);
|
|
3512
|
-
}
|
|
3513
3561
|
if (Object.keys(filter.metadata || {}).length === 0) delete filter.metadata;
|
|
3514
3562
|
if (filter.keywords && filter.keywords.length === 0) delete filter.keywords;
|
|
3515
3563
|
return filter;
|
|
@@ -3517,10 +3565,40 @@ var QueryProcessor = class {
|
|
|
3517
3565
|
};
|
|
3518
3566
|
|
|
3519
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
|
+
};
|
|
3520
3597
|
var Pipeline = class {
|
|
3521
3598
|
constructor(config) {
|
|
3522
3599
|
this.config = config;
|
|
3523
|
-
|
|
3600
|
+
/** LRU-bounded cache: avoids re-embedding identical queries within the same process. */
|
|
3601
|
+
this.embeddingCache = new LRUEmbeddingCache(500);
|
|
3524
3602
|
this.initialised = false;
|
|
3525
3603
|
var _a, _b, _c, _d, _e;
|
|
3526
3604
|
this.chunker = new DocumentChunker(
|
|
@@ -3608,6 +3686,7 @@ var Pipeline = class {
|
|
|
3608
3686
|
}
|
|
3609
3687
|
/**
|
|
3610
3688
|
* Step 2: Generate embeddings for chunks with retry logic.
|
|
3689
|
+
* Uses batchEmbed when available for efficiency; falls back to sequential embedding.
|
|
3611
3690
|
*/
|
|
3612
3691
|
async processEmbeddings(chunks) {
|
|
3613
3692
|
const embedBatchOptions = {
|
|
@@ -3621,7 +3700,9 @@ var Pipeline = class {
|
|
|
3621
3700
|
embedBatchOptions
|
|
3622
3701
|
);
|
|
3623
3702
|
if (vectors.length !== chunks.length) {
|
|
3624
|
-
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
|
+
);
|
|
3625
3706
|
}
|
|
3626
3707
|
return vectors;
|
|
3627
3708
|
}
|
|
@@ -3775,6 +3856,7 @@ ${context}`;
|
|
|
3775
3856
|
}
|
|
3776
3857
|
/**
|
|
3777
3858
|
* Universal retrieval method combining all enabled providers.
|
|
3859
|
+
* Uses an LRU-bounded embedding cache to avoid re-embedding the same query.
|
|
3778
3860
|
*/
|
|
3779
3861
|
async retrieve(query, options) {
|
|
3780
3862
|
var _a, _b, _c;
|
|
@@ -3807,10 +3889,13 @@ ${history.map((m) => `${m.role}: ${m.content}`).join("\n")}
|
|
|
3807
3889
|
New Question: ${question}
|
|
3808
3890
|
|
|
3809
3891
|
Optimized Search Query:`;
|
|
3810
|
-
const rewrite = await this.llmProvider.chat(
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
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
|
+
);
|
|
3814
3899
|
return rewrite.trim() || question;
|
|
3815
3900
|
}
|
|
3816
3901
|
};
|
|
@@ -3971,21 +4056,11 @@ var VectorPlugin = class {
|
|
|
3971
4056
|
|
|
3972
4057
|
// src/config/ConfigBuilder.ts
|
|
3973
4058
|
var ConfigBuilder = class {
|
|
3974
|
-
constructor() {
|
|
3975
|
-
this.config = {
|
|
3976
|
-
projectId: "default-project",
|
|
3977
|
-
rag: {
|
|
3978
|
-
chunkSize: 1e3,
|
|
3979
|
-
chunkOverlap: 200,
|
|
3980
|
-
topK: 5
|
|
3981
|
-
}
|
|
3982
|
-
};
|
|
3983
|
-
}
|
|
3984
4059
|
/**
|
|
3985
4060
|
* Set the project/application ID for namespacing
|
|
3986
4061
|
*/
|
|
3987
4062
|
projectId(id) {
|
|
3988
|
-
this.
|
|
4063
|
+
this._projectId = id;
|
|
3989
4064
|
return this;
|
|
3990
4065
|
}
|
|
3991
4066
|
/**
|
|
@@ -3994,9 +4069,9 @@ var ConfigBuilder = class {
|
|
|
3994
4069
|
vectorDb(provider, options) {
|
|
3995
4070
|
var _a;
|
|
3996
4071
|
if (provider === "auto") {
|
|
3997
|
-
this.
|
|
4072
|
+
this._vectorDb = this._autoDetectVectorDb();
|
|
3998
4073
|
} else {
|
|
3999
|
-
this.
|
|
4074
|
+
this._vectorDb = {
|
|
4000
4075
|
provider,
|
|
4001
4076
|
indexName: (_a = options == null ? void 0 : options.indexName) != null ? _a : "default",
|
|
4002
4077
|
options: __spreadValues({}, options)
|
|
@@ -4010,9 +4085,9 @@ var ConfigBuilder = class {
|
|
|
4010
4085
|
llm(provider, model, apiKey, options) {
|
|
4011
4086
|
var _a, _b;
|
|
4012
4087
|
if (provider === "auto") {
|
|
4013
|
-
this.
|
|
4088
|
+
this._llm = this._autoDetectLLM();
|
|
4014
4089
|
} else {
|
|
4015
|
-
this.
|
|
4090
|
+
this._llm = {
|
|
4016
4091
|
provider,
|
|
4017
4092
|
model: model != null ? model : "default-model",
|
|
4018
4093
|
apiKey,
|
|
@@ -4030,9 +4105,9 @@ var ConfigBuilder = class {
|
|
|
4030
4105
|
*/
|
|
4031
4106
|
embedding(provider, model, apiKey, options) {
|
|
4032
4107
|
if (provider === "auto") {
|
|
4033
|
-
this.
|
|
4108
|
+
this._embedding = this._autoDetectEmbedding();
|
|
4034
4109
|
} else {
|
|
4035
|
-
this.
|
|
4110
|
+
this._embedding = {
|
|
4036
4111
|
provider,
|
|
4037
4112
|
model: model != null ? model : "default-embedding",
|
|
4038
4113
|
apiKey,
|
|
@@ -4043,26 +4118,46 @@ var ConfigBuilder = class {
|
|
|
4043
4118
|
return this;
|
|
4044
4119
|
}
|
|
4045
4120
|
/**
|
|
4046
|
-
* Set RAG-specific parameters
|
|
4121
|
+
* Set RAG-specific pipeline parameters
|
|
4047
4122
|
*/
|
|
4048
4123
|
rag(options) {
|
|
4049
4124
|
var _a;
|
|
4050
|
-
this.
|
|
4125
|
+
this._rag = __spreadValues(__spreadValues({}, (_a = this._rag) != null ? _a : {}), options);
|
|
4051
4126
|
return this;
|
|
4052
4127
|
}
|
|
4053
4128
|
/**
|
|
4054
|
-
* Set UI
|
|
4129
|
+
* Set UI branding and appearance options.
|
|
4130
|
+
* Accepts the full UIConfig interface.
|
|
4055
4131
|
*/
|
|
4056
4132
|
ui(options) {
|
|
4057
|
-
this.
|
|
4133
|
+
this._ui = options;
|
|
4058
4134
|
return this;
|
|
4059
4135
|
}
|
|
4060
4136
|
/**
|
|
4061
|
-
* Build and return the
|
|
4137
|
+
* Build and return the final RagConfig.
|
|
4138
|
+
* Throws if required fields (projectId, vectorDb, llm, embedding) are not set.
|
|
4062
4139
|
*/
|
|
4063
4140
|
build() {
|
|
4064
|
-
|
|
4065
|
-
|
|
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 } : {});
|
|
4066
4161
|
}
|
|
4067
4162
|
/**
|
|
4068
4163
|
* Build and return as JSON for serialization
|
|
@@ -4073,169 +4168,58 @@ var ConfigBuilder = class {
|
|
|
4073
4168
|
// ============================================================================
|
|
4074
4169
|
// Private helper methods for auto-detection
|
|
4075
4170
|
// ============================================================================
|
|
4076
|
-
|
|
4171
|
+
_autoDetectVectorDb() {
|
|
4077
4172
|
if (process.env.PINECONE_API_KEY && process.env.PINECONE_INDEX) {
|
|
4078
|
-
return {
|
|
4079
|
-
provider: "pinecone",
|
|
4080
|
-
indexName: process.env.PINECONE_INDEX,
|
|
4081
|
-
options: { apiKey: process.env.PINECONE_API_KEY }
|
|
4082
|
-
};
|
|
4173
|
+
return { provider: "pinecone", indexName: process.env.PINECONE_INDEX, options: { apiKey: process.env.PINECONE_API_KEY } };
|
|
4083
4174
|
}
|
|
4084
4175
|
if (process.env.QDRANT_URL) {
|
|
4085
|
-
return {
|
|
4086
|
-
provider: "qdrant",
|
|
4087
|
-
indexName: process.env.QDRANT_COLLECTION || "documents",
|
|
4088
|
-
options: {
|
|
4089
|
-
url: process.env.QDRANT_URL,
|
|
4090
|
-
apiKey: process.env.QDRANT_API_KEY
|
|
4091
|
-
}
|
|
4092
|
-
};
|
|
4176
|
+
return { provider: "qdrant", indexName: process.env.QDRANT_COLLECTION || "documents", options: { url: process.env.QDRANT_URL, apiKey: process.env.QDRANT_API_KEY } };
|
|
4093
4177
|
}
|
|
4094
4178
|
if (process.env.DATABASE_URL) {
|
|
4095
|
-
return {
|
|
4096
|
-
provider: "postgresql",
|
|
4097
|
-
indexName: process.env.PG_TABLE || "documents",
|
|
4098
|
-
options: {
|
|
4099
|
-
connectionString: process.env.DATABASE_URL
|
|
4100
|
-
}
|
|
4101
|
-
};
|
|
4179
|
+
return { provider: "postgresql", indexName: process.env.PG_TABLE || "documents", options: { connectionString: process.env.DATABASE_URL } };
|
|
4102
4180
|
}
|
|
4103
4181
|
if (process.env.MONGODB_URI) {
|
|
4104
|
-
return {
|
|
4105
|
-
provider: "mongodb",
|
|
4106
|
-
indexName: process.env.MONGODB_COLLECTION || "documents",
|
|
4107
|
-
options: {
|
|
4108
|
-
uri: process.env.MONGODB_URI,
|
|
4109
|
-
database: process.env.MONGODB_DB || "ai_db",
|
|
4110
|
-
collection: process.env.MONGODB_COLLECTION || "documents"
|
|
4111
|
-
}
|
|
4112
|
-
};
|
|
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" } };
|
|
4113
4183
|
}
|
|
4114
4184
|
if (process.env.REDIS_URL) {
|
|
4115
|
-
return {
|
|
4116
|
-
provider: "redis",
|
|
4117
|
-
indexName: process.env.REDIS_INDEX || "documents",
|
|
4118
|
-
options: {
|
|
4119
|
-
url: process.env.REDIS_URL
|
|
4120
|
-
}
|
|
4121
|
-
};
|
|
4185
|
+
return { provider: "redis", indexName: process.env.REDIS_INDEX || "documents", options: { url: process.env.REDIS_URL } };
|
|
4122
4186
|
}
|
|
4123
|
-
return {
|
|
4124
|
-
provider: "qdrant",
|
|
4125
|
-
indexName: "documents",
|
|
4126
|
-
options: {
|
|
4127
|
-
url: process.env.QDRANT_URL || "http://localhost:6333"
|
|
4128
|
-
}
|
|
4129
|
-
};
|
|
4187
|
+
return { provider: "qdrant", indexName: "documents", options: { url: process.env.QDRANT_URL || "http://localhost:6333" } };
|
|
4130
4188
|
}
|
|
4131
|
-
|
|
4189
|
+
_autoDetectLLM() {
|
|
4132
4190
|
if (process.env.OPENAI_API_KEY) {
|
|
4133
|
-
return {
|
|
4134
|
-
provider: "openai",
|
|
4135
|
-
model: process.env.OPENAI_MODEL || "gpt-4o-mini",
|
|
4136
|
-
apiKey: process.env.OPENAI_API_KEY,
|
|
4137
|
-
maxTokens: parseInt(process.env.OPENAI_MAX_TOKENS || "1024"),
|
|
4138
|
-
temperature: parseFloat(process.env.OPENAI_TEMPERATURE || "0.7")
|
|
4139
|
-
};
|
|
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") };
|
|
4140
4192
|
}
|
|
4141
4193
|
if (process.env.ANTHROPIC_API_KEY) {
|
|
4142
|
-
return {
|
|
4143
|
-
provider: "anthropic",
|
|
4144
|
-
model: process.env.ANTHROPIC_MODEL || "claude-3-haiku-20240307",
|
|
4145
|
-
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
4146
|
-
maxTokens: parseInt(process.env.ANTHROPIC_MAX_TOKENS || "1024"),
|
|
4147
|
-
temperature: parseFloat(process.env.ANTHROPIC_TEMPERATURE || "0.7")
|
|
4148
|
-
};
|
|
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") };
|
|
4149
4195
|
}
|
|
4150
4196
|
if (process.env.OLLAMA_BASE_URL) {
|
|
4151
|
-
return {
|
|
4152
|
-
provider: "ollama",
|
|
4153
|
-
model: process.env.OLLAMA_MODEL || "mistral",
|
|
4154
|
-
baseUrl: process.env.OLLAMA_BASE_URL,
|
|
4155
|
-
maxTokens: parseInt(process.env.OLLAMA_MAX_TOKENS || "1024"),
|
|
4156
|
-
temperature: parseFloat(process.env.OLLAMA_TEMPERATURE || "0.7")
|
|
4157
|
-
};
|
|
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") };
|
|
4158
4198
|
}
|
|
4159
|
-
return {
|
|
4160
|
-
provider: "openai",
|
|
4161
|
-
model: "gpt-4o-mini",
|
|
4162
|
-
apiKey: process.env.OPENAI_API_KEY
|
|
4163
|
-
};
|
|
4199
|
+
return { provider: "openai", model: "gpt-4o-mini", apiKey: process.env.OPENAI_API_KEY };
|
|
4164
4200
|
}
|
|
4165
|
-
|
|
4201
|
+
_autoDetectEmbedding() {
|
|
4166
4202
|
if (process.env.EMBEDDING_PROVIDER) {
|
|
4167
|
-
|
|
4168
|
-
return {
|
|
4169
|
-
provider,
|
|
4170
|
-
model: process.env.EMBEDDING_MODEL || "default",
|
|
4171
|
-
apiKey: process.env.EMBEDDING_API_KEY,
|
|
4172
|
-
baseUrl: process.env.EMBEDDING_BASE_URL
|
|
4173
|
-
};
|
|
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 };
|
|
4174
4204
|
}
|
|
4175
|
-
return {
|
|
4176
|
-
provider: "openai",
|
|
4177
|
-
model: "text-embedding-3-small",
|
|
4178
|
-
apiKey: process.env.OPENAI_API_KEY
|
|
4179
|
-
};
|
|
4205
|
+
return { provider: "openai", model: "text-embedding-3-small", apiKey: process.env.OPENAI_API_KEY };
|
|
4180
4206
|
}
|
|
4181
4207
|
};
|
|
4182
4208
|
var PRESETS = {
|
|
4183
|
-
/**
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
"
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
},
|
|
4191
|
-
/**
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
"
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
embedding: "openai"
|
|
4198
|
-
},
|
|
4199
|
-
/**
|
|
4200
|
-
* Local development: Ollama + local Qdrant
|
|
4201
|
-
*/
|
|
4202
|
-
"local-dev": {
|
|
4203
|
-
vectorDb: "qdrant",
|
|
4204
|
-
llm: "ollama",
|
|
4205
|
-
embedding: "ollama"
|
|
4206
|
-
},
|
|
4207
|
-
/**
|
|
4208
|
-
* Fully open-source: Ollama LLM + Qdrant vector DB + Ollama embeddings
|
|
4209
|
-
*/
|
|
4210
|
-
"fully-open-source": {
|
|
4211
|
-
vectorDb: "qdrant",
|
|
4212
|
-
llm: "ollama",
|
|
4213
|
-
embedding: "ollama"
|
|
4214
|
-
},
|
|
4215
|
-
/**
|
|
4216
|
-
* PostgreSQL stack: pgvector + OpenAI
|
|
4217
|
-
*/
|
|
4218
|
-
"postgres-openai": {
|
|
4219
|
-
vectorDb: "postgresql",
|
|
4220
|
-
llm: "openai",
|
|
4221
|
-
embedding: "openai"
|
|
4222
|
-
},
|
|
4223
|
-
/**
|
|
4224
|
-
* Enterprise MongoDB: MongoDB Atlas with OpenAI
|
|
4225
|
-
*/
|
|
4226
|
-
"mongodb-openai": {
|
|
4227
|
-
vectorDb: "mongodb",
|
|
4228
|
-
llm: "openai",
|
|
4229
|
-
embedding: "openai"
|
|
4230
|
-
},
|
|
4231
|
-
/**
|
|
4232
|
-
* Redis stack for caching + search
|
|
4233
|
-
*/
|
|
4234
|
-
"redis-openai": {
|
|
4235
|
-
vectorDb: "redis",
|
|
4236
|
-
llm: "openai",
|
|
4237
|
-
embedding: "openai"
|
|
4238
|
-
}
|
|
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" }
|
|
4239
4223
|
};
|
|
4240
4224
|
function createFromPreset(presetName) {
|
|
4241
4225
|
const preset = PRESETS[presetName];
|
|
@@ -4514,8 +4498,35 @@ init_UniversalVectorProvider();
|
|
|
4514
4498
|
|
|
4515
4499
|
// src/handlers/index.ts
|
|
4516
4500
|
var import_server = require("next/server");
|
|
4517
|
-
function
|
|
4518
|
-
|
|
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);
|
|
4519
4530
|
return async function POST(req) {
|
|
4520
4531
|
try {
|
|
4521
4532
|
const body = await req.json();
|
|
@@ -4531,8 +4542,64 @@ function createChatHandler(config) {
|
|
|
4531
4542
|
}
|
|
4532
4543
|
};
|
|
4533
4544
|
}
|
|
4534
|
-
function
|
|
4535
|
-
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);
|
|
4536
4603
|
return async function POST(req) {
|
|
4537
4604
|
try {
|
|
4538
4605
|
const body = await req.json();
|
|
@@ -4548,8 +4615,8 @@ function createIngestHandler(config) {
|
|
|
4548
4615
|
}
|
|
4549
4616
|
};
|
|
4550
4617
|
}
|
|
4551
|
-
function createHealthHandler(
|
|
4552
|
-
const plugin = new VectorPlugin(
|
|
4618
|
+
function createHealthHandler(configOrPlugin) {
|
|
4619
|
+
const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
|
|
4553
4620
|
return async function GET() {
|
|
4554
4621
|
try {
|
|
4555
4622
|
const health = await plugin.checkHealth();
|
|
@@ -4565,8 +4632,8 @@ function createHealthHandler(config) {
|
|
|
4565
4632
|
}
|
|
4566
4633
|
};
|
|
4567
4634
|
}
|
|
4568
|
-
function createUploadHandler(
|
|
4569
|
-
const plugin = new VectorPlugin(
|
|
4635
|
+
function createUploadHandler(configOrPlugin) {
|
|
4636
|
+
const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
|
|
4570
4637
|
return async function POST(req) {
|
|
4571
4638
|
try {
|
|
4572
4639
|
const formData = await req.formData();
|
|
@@ -4635,6 +4702,12 @@ function createUploadHandler(config) {
|
|
|
4635
4702
|
createFromPreset,
|
|
4636
4703
|
createHealthHandler,
|
|
4637
4704
|
createIngestHandler,
|
|
4705
|
+
createStreamHandler,
|
|
4638
4706
|
createUploadHandler,
|
|
4639
|
-
getRagConfig
|
|
4707
|
+
getRagConfig,
|
|
4708
|
+
resetConfigCache,
|
|
4709
|
+
sseErrorFrame,
|
|
4710
|
+
sseFrame,
|
|
4711
|
+
sseMetaFrame,
|
|
4712
|
+
sseTextFrame
|
|
4640
4713
|
});
|