@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.
- package/dist/DocumentChunker-Dh9TvmGG.d.mts +45 -0
- package/dist/DocumentChunker-Dh9TvmGG.d.ts +45 -0
- package/dist/{RagConfig-DRJO4hGU.d.mts → RagConfig-BjC6zSTV.d.mts} +62 -1
- package/dist/{RagConfig-DRJO4hGU.d.ts → RagConfig-BjC6zSTV.d.ts} +62 -1
- package/dist/{chunk-6MLZHQZT.mjs → chunk-ZCDJSGUW.mjs} +237 -104
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +239 -106
- package/dist/handlers/index.mjs +11 -3
- package/dist/index-C3bLmWcR.d.ts +206 -0
- package/dist/index-CU_fQq__.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 +319 -221
- 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/RagConfig.ts +4 -0
- 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 +64 -8
- package/src/core/ProviderRegistry.ts +2 -2
- package/src/core/QueryProcessor.ts +45 -12
- 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/handlers/index.js
CHANGED
|
@@ -1508,7 +1508,11 @@ __export(handlers_exports, {
|
|
|
1508
1508
|
createHealthHandler: () => createHealthHandler,
|
|
1509
1509
|
createIngestHandler: () => createIngestHandler,
|
|
1510
1510
|
createStreamHandler: () => createStreamHandler,
|
|
1511
|
-
createUploadHandler: () => createUploadHandler
|
|
1511
|
+
createUploadHandler: () => createUploadHandler,
|
|
1512
|
+
sseErrorFrame: () => sseErrorFrame,
|
|
1513
|
+
sseFrame: () => sseFrame,
|
|
1514
|
+
sseMetaFrame: () => sseMetaFrame,
|
|
1515
|
+
sseTextFrame: () => sseTextFrame
|
|
1512
1516
|
});
|
|
1513
1517
|
module.exports = __toCommonJS(handlers_exports);
|
|
1514
1518
|
var import_server = require("next/server");
|
|
@@ -1691,13 +1695,20 @@ function getRagConfig(env = process.env) {
|
|
|
1691
1695
|
}
|
|
1692
1696
|
|
|
1693
1697
|
// src/core/ConfigResolver.ts
|
|
1698
|
+
var _cachedEnvConfig = null;
|
|
1699
|
+
function getCachedEnvConfig() {
|
|
1700
|
+
if (!_cachedEnvConfig) {
|
|
1701
|
+
_cachedEnvConfig = getRagConfig();
|
|
1702
|
+
}
|
|
1703
|
+
return _cachedEnvConfig;
|
|
1704
|
+
}
|
|
1694
1705
|
var ConfigResolver = class {
|
|
1695
1706
|
/**
|
|
1696
|
-
* Resolves the final configuration by merging host-provided config with defaults.
|
|
1707
|
+
* Resolves the final configuration by merging host-provided config with environment defaults.
|
|
1697
1708
|
* @param hostConfig - Partial configuration passed from the host application.
|
|
1698
1709
|
*/
|
|
1699
1710
|
static resolve(hostConfig) {
|
|
1700
|
-
const envConfig =
|
|
1711
|
+
const envConfig = getCachedEnvConfig();
|
|
1701
1712
|
if (!hostConfig) {
|
|
1702
1713
|
return envConfig;
|
|
1703
1714
|
}
|
|
@@ -2971,14 +2982,16 @@ var LangChainAgent = class {
|
|
|
2971
2982
|
this.config = config;
|
|
2972
2983
|
}
|
|
2973
2984
|
/**
|
|
2974
|
-
* Initializes the agent with the RAG pipeline as a
|
|
2975
|
-
* Dynamically imports
|
|
2985
|
+
* Initializes the LangChain ReAct agent with the RAG pipeline as a tool.
|
|
2986
|
+
* Dynamically imports langchain so the package doesn't crash if it isn't installed.
|
|
2976
2987
|
*/
|
|
2977
2988
|
async initialize(chatModel) {
|
|
2978
2989
|
try {
|
|
2979
|
-
const { DynamicTool } = await
|
|
2980
|
-
|
|
2981
|
-
|
|
2990
|
+
const [{ DynamicTool }, { HumanMessage }, { createAgent }] = await Promise.all([
|
|
2991
|
+
import("@langchain/core/tools"),
|
|
2992
|
+
import("@langchain/core/messages"),
|
|
2993
|
+
import("langchain")
|
|
2994
|
+
]);
|
|
2982
2995
|
const searchTool = new DynamicTool({
|
|
2983
2996
|
name: "document_search",
|
|
2984
2997
|
description: "Use this tool to search through the knowledge base and document repository. Input should be a specific search query.",
|
|
@@ -2987,42 +3000,53 @@ var LangChainAgent = class {
|
|
|
2987
3000
|
return `Search Results:
|
|
2988
3001
|
${response.reply}
|
|
2989
3002
|
|
|
2990
|
-
Sources Used: ${JSON.stringify(
|
|
3003
|
+
Sources Used: ${JSON.stringify(
|
|
3004
|
+
response.sources.map((s) => s.id)
|
|
3005
|
+
)}`;
|
|
2991
3006
|
}
|
|
2992
3007
|
});
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
new MessagesPlaceholder("agent_scratchpad")
|
|
2999
|
-
]);
|
|
3000
|
-
const agent = await createOpenAIFunctionsAgent({
|
|
3001
|
-
llm: chatModel,
|
|
3002
|
-
tools,
|
|
3003
|
-
prompt
|
|
3004
|
-
});
|
|
3005
|
-
this.executor = new AgentExecutor({
|
|
3006
|
-
agent,
|
|
3007
|
-
tools
|
|
3008
|
+
this.agent = createAgent({
|
|
3009
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
3010
|
+
model: chatModel,
|
|
3011
|
+
tools: [searchTool],
|
|
3012
|
+
systemPrompt: this.config.llm.systemPrompt || "You are a helpful AI assistant with access to a document search tool."
|
|
3008
3013
|
});
|
|
3014
|
+
void HumanMessage;
|
|
3009
3015
|
} catch (error) {
|
|
3010
|
-
|
|
3011
|
-
|
|
3016
|
+
const isMissing = error instanceof Error && error.message.includes("Cannot find module");
|
|
3017
|
+
const hint = isMissing ? " Make sure 'langchain' and '@langchain/core' are installed:\n npm install langchain @langchain/core" : "";
|
|
3018
|
+
throw new Error(
|
|
3019
|
+
`[LangChainAgent] Failed to initialize.${hint}
|
|
3020
|
+
${error instanceof Error ? error.message : String(error)}`
|
|
3021
|
+
);
|
|
3012
3022
|
}
|
|
3013
3023
|
}
|
|
3014
3024
|
/**
|
|
3015
3025
|
* Run the agentic flow.
|
|
3026
|
+
*
|
|
3027
|
+
* LangChain v1.x: invoke takes `{ messages: [...] }` instead of `{ input, chat_history }`.
|
|
3028
|
+
* The agent returns `{ messages: [...] }` — the last message is the final answer.
|
|
3016
3029
|
*/
|
|
3017
3030
|
async run(input, chatHistory = []) {
|
|
3018
|
-
|
|
3031
|
+
var _a, _b, _c;
|
|
3032
|
+
if (!this.agent) {
|
|
3019
3033
|
throw new Error("[LangChainAgent] Agent not initialized. Call initialize() first.");
|
|
3020
3034
|
}
|
|
3021
|
-
const
|
|
3022
|
-
|
|
3023
|
-
|
|
3035
|
+
const { HumanMessage, AIMessage } = await import("@langchain/core/messages");
|
|
3036
|
+
const historyMessages = chatHistory.map(
|
|
3037
|
+
(m) => m.role === "user" ? new HumanMessage(m.content) : new AIMessage(m.content)
|
|
3038
|
+
);
|
|
3039
|
+
const response = await this.agent.invoke({
|
|
3040
|
+
messages: [...historyMessages, new HumanMessage(input)]
|
|
3024
3041
|
});
|
|
3025
|
-
|
|
3042
|
+
const lastMessage = (_a = response == null ? void 0 : response.messages) == null ? void 0 : _a.at(-1);
|
|
3043
|
+
if (lastMessage && typeof lastMessage.content === "string") {
|
|
3044
|
+
return lastMessage.content;
|
|
3045
|
+
}
|
|
3046
|
+
if (Array.isArray(lastMessage == null ? void 0 : lastMessage.content)) {
|
|
3047
|
+
return lastMessage.content.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
3048
|
+
}
|
|
3049
|
+
return String((_c = (_b = response == null ? void 0 : response.output) != null ? _b : response) != null ? _c : "");
|
|
3026
3050
|
}
|
|
3027
3051
|
};
|
|
3028
3052
|
|
|
@@ -3338,15 +3362,18 @@ var QueryProcessor = class {
|
|
|
3338
3362
|
* Checks if a string is likely a question word or common prompt phrase.
|
|
3339
3363
|
*/
|
|
3340
3364
|
static isLikelyPromptPhrase(value) {
|
|
3341
|
-
return /^(what|which|who|where|when|why|how)\b/i.test(value.trim());
|
|
3365
|
+
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());
|
|
3342
3366
|
}
|
|
3343
3367
|
/**
|
|
3344
3368
|
* Scans a natural language question for potential metadata hints and keywords.
|
|
3369
|
+
* @param question The user's query
|
|
3370
|
+
* @param validFields Optional list of known filterable fields to look for
|
|
3345
3371
|
*/
|
|
3346
|
-
static extractQueryFieldHints(question) {
|
|
3372
|
+
static extractQueryFieldHints(question, validFields = []) {
|
|
3347
3373
|
var _a, _b, _c, _d;
|
|
3348
3374
|
if (!question.trim()) return [];
|
|
3349
3375
|
const hints = /* @__PURE__ */ new Map();
|
|
3376
|
+
const fieldsToSearch = [.../* @__PURE__ */ new Set([...this.COMMON_METADATA_FIELDS, ...validFields])];
|
|
3350
3377
|
const addHint = (value, field) => {
|
|
3351
3378
|
const normalizedValue = this.normalizeHintValue(value);
|
|
3352
3379
|
if (!normalizedValue) return;
|
|
@@ -3377,11 +3404,28 @@ var QueryProcessor = class {
|
|
|
3377
3404
|
if (name) addHint(name, "name");
|
|
3378
3405
|
}
|
|
3379
3406
|
}
|
|
3407
|
+
if (fieldsToSearch.length > 0) {
|
|
3408
|
+
for (const field of fieldsToSearch) {
|
|
3409
|
+
const forwardPattern = new RegExp(`\\b${field}\\s*(?:is|are|:|of)?\\s+["']?([^"\\n?.!,]{2,60})["']?(?=[?.!,]|$)`, "gi");
|
|
3410
|
+
for (const match of question.matchAll(forwardPattern)) {
|
|
3411
|
+
const value = match[1];
|
|
3412
|
+
if (value && !this.isLikelyPromptPhrase(value)) {
|
|
3413
|
+
addHint(value, field);
|
|
3414
|
+
}
|
|
3415
|
+
}
|
|
3416
|
+
const reversePattern = new RegExp(`\\b([^"\\n?.!,\\s]{2,60})\\s+${field}\\b`, "gi");
|
|
3417
|
+
for (const match of question.matchAll(reversePattern)) {
|
|
3418
|
+
const value = match[1];
|
|
3419
|
+
if (value && !this.isLikelyPromptPhrase(value)) {
|
|
3420
|
+
addHint(value, field);
|
|
3421
|
+
}
|
|
3422
|
+
}
|
|
3423
|
+
}
|
|
3424
|
+
}
|
|
3380
3425
|
const universalPatterns = [
|
|
3381
3426
|
{ regex: /([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/gi, field: "email", group: 1 },
|
|
3382
3427
|
{ regex: /(\+?\d[\d\-\.\s\(\)]{6,}\d)/g, field: "phone", group: 1 },
|
|
3383
3428
|
{ 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 },
|
|
3384
|
-
{ regex: /(\$\s?\d{1,3}(?:,\d{3})*(?:\.\d+)?)/g, field: "amount", group: 1 },
|
|
3385
3429
|
{ regex: /\b(ID|id|identifier)[: ]\s*([A-Za-z0-9\-]{3,})\b/gi, field: "id", group: 2 },
|
|
3386
3430
|
{ regex: /"([^"]{2,120})"/g, group: 1 },
|
|
3387
3431
|
{ regex: /'([^']{2,120})'/g, group: 1 }
|
|
@@ -3425,6 +3469,10 @@ var QueryProcessor = class {
|
|
|
3425
3469
|
}
|
|
3426
3470
|
/**
|
|
3427
3471
|
* Constructs a QueryFilter object from extracted hints.
|
|
3472
|
+
*
|
|
3473
|
+
* Note: proper nouns are extracted inside `extractQueryFieldHints` and surfaced
|
|
3474
|
+
* as field-less hints; `buildQueryFilter` adds them to `keywords` without
|
|
3475
|
+
* re-running the proper noun regex to avoid duplication.
|
|
3428
3476
|
*/
|
|
3429
3477
|
static buildQueryFilter(question, hints) {
|
|
3430
3478
|
const filter = { metadata: {}, keywords: [], queryText: question };
|
|
@@ -3432,24 +3480,74 @@ var QueryProcessor = class {
|
|
|
3432
3480
|
if (hint.field) {
|
|
3433
3481
|
filter.metadata[hint.field] = hint.value;
|
|
3434
3482
|
} else {
|
|
3435
|
-
filter.keywords.
|
|
3483
|
+
if (!filter.keywords.includes(hint.value)) {
|
|
3484
|
+
filter.keywords.push(hint.value);
|
|
3485
|
+
}
|
|
3436
3486
|
}
|
|
3437
3487
|
}
|
|
3438
|
-
for (const match of question.matchAll(/\b[A-Z][a-z]+(?:\s+[A-Z][a-z]+){0,3}\b/g)) {
|
|
3439
|
-
const term = this.normalizeHintValue(match[0]);
|
|
3440
|
-
if (term && !filter.keywords.includes(term)) filter.keywords.push(term);
|
|
3441
|
-
}
|
|
3442
3488
|
if (Object.keys(filter.metadata || {}).length === 0) delete filter.metadata;
|
|
3443
3489
|
if (filter.keywords && filter.keywords.length === 0) delete filter.keywords;
|
|
3444
3490
|
return filter;
|
|
3445
3491
|
}
|
|
3446
3492
|
};
|
|
3493
|
+
QueryProcessor.COMMON_METADATA_FIELDS = [
|
|
3494
|
+
"category",
|
|
3495
|
+
"type",
|
|
3496
|
+
"brand",
|
|
3497
|
+
"status",
|
|
3498
|
+
"priority",
|
|
3499
|
+
"id",
|
|
3500
|
+
"name",
|
|
3501
|
+
"email",
|
|
3502
|
+
"phone",
|
|
3503
|
+
"price",
|
|
3504
|
+
"rating",
|
|
3505
|
+
"color",
|
|
3506
|
+
"size",
|
|
3507
|
+
"material",
|
|
3508
|
+
"sku",
|
|
3509
|
+
"role",
|
|
3510
|
+
"department",
|
|
3511
|
+
"location",
|
|
3512
|
+
"tag",
|
|
3513
|
+
"label"
|
|
3514
|
+
];
|
|
3447
3515
|
|
|
3448
3516
|
// src/core/Pipeline.ts
|
|
3517
|
+
var LRUEmbeddingCache = class {
|
|
3518
|
+
constructor(maxSize = 500) {
|
|
3519
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
3520
|
+
this.maxSize = maxSize;
|
|
3521
|
+
}
|
|
3522
|
+
get(key) {
|
|
3523
|
+
const value = this.cache.get(key);
|
|
3524
|
+
if (value !== void 0) {
|
|
3525
|
+
this.cache.delete(key);
|
|
3526
|
+
this.cache.set(key, value);
|
|
3527
|
+
}
|
|
3528
|
+
return value;
|
|
3529
|
+
}
|
|
3530
|
+
set(key, value) {
|
|
3531
|
+
if (this.cache.has(key)) {
|
|
3532
|
+
this.cache.delete(key);
|
|
3533
|
+
} else if (this.cache.size >= this.maxSize) {
|
|
3534
|
+
const oldestKey = this.cache.keys().next().value;
|
|
3535
|
+
if (oldestKey !== void 0) this.cache.delete(oldestKey);
|
|
3536
|
+
}
|
|
3537
|
+
this.cache.set(key, value);
|
|
3538
|
+
}
|
|
3539
|
+
clear() {
|
|
3540
|
+
this.cache.clear();
|
|
3541
|
+
}
|
|
3542
|
+
get size() {
|
|
3543
|
+
return this.cache.size;
|
|
3544
|
+
}
|
|
3545
|
+
};
|
|
3449
3546
|
var Pipeline = class {
|
|
3450
3547
|
constructor(config) {
|
|
3451
3548
|
this.config = config;
|
|
3452
|
-
|
|
3549
|
+
/** LRU-bounded cache: avoids re-embedding identical queries within the same process. */
|
|
3550
|
+
this.embeddingCache = new LRUEmbeddingCache(500);
|
|
3453
3551
|
this.initialised = false;
|
|
3454
3552
|
var _a, _b, _c, _d, _e;
|
|
3455
3553
|
this.chunker = new DocumentChunker(
|
|
@@ -3537,6 +3635,7 @@ var Pipeline = class {
|
|
|
3537
3635
|
}
|
|
3538
3636
|
/**
|
|
3539
3637
|
* Step 2: Generate embeddings for chunks with retry logic.
|
|
3638
|
+
* Uses batchEmbed when available for efficiency; falls back to sequential embedding.
|
|
3540
3639
|
*/
|
|
3541
3640
|
async processEmbeddings(chunks) {
|
|
3542
3641
|
const embedBatchOptions = {
|
|
@@ -3550,7 +3649,9 @@ var Pipeline = class {
|
|
|
3550
3649
|
embedBatchOptions
|
|
3551
3650
|
);
|
|
3552
3651
|
if (vectors.length !== chunks.length) {
|
|
3553
|
-
throw new Error(
|
|
3652
|
+
throw new Error(
|
|
3653
|
+
`[Pipeline] Embedding mismatch: got ${vectors.length} vectors for ${chunks.length} chunks. Check embedding provider logs for individual chunk failures.`
|
|
3654
|
+
);
|
|
3554
3655
|
}
|
|
3555
3656
|
return vectors;
|
|
3556
3657
|
}
|
|
@@ -3640,7 +3741,7 @@ var Pipeline = class {
|
|
|
3640
3741
|
*/
|
|
3641
3742
|
askStream(_0) {
|
|
3642
3743
|
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
3643
|
-
var _a, _b, _c, _d, _e, _f;
|
|
3744
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
3644
3745
|
yield new __await(this.initialize());
|
|
3645
3746
|
const ns = namespace != null ? namespace : this.config.projectId;
|
|
3646
3747
|
const topK = (_b = (_a = this.config.rag) == null ? void 0 : _a.topK) != null ? _b : 5;
|
|
@@ -3650,7 +3751,7 @@ var Pipeline = class {
|
|
|
3650
3751
|
if ((_e = this.config.rag) == null ? void 0 : _e.useQueryTransformation) {
|
|
3651
3752
|
searchQuery = yield new __await(this.rewriteQuery(question, history));
|
|
3652
3753
|
}
|
|
3653
|
-
const hints = QueryProcessor.extractQueryFieldHints(question);
|
|
3754
|
+
const hints = QueryProcessor.extractQueryFieldHints(question, (_f = this.config.rag) == null ? void 0 : _f.filterableFields);
|
|
3654
3755
|
const filter = QueryProcessor.buildQueryFilter(question, hints);
|
|
3655
3756
|
const { sources: rawSources, graphData } = yield new __await(this.retrieve(searchQuery, {
|
|
3656
3757
|
namespace: ns,
|
|
@@ -3658,7 +3759,7 @@ var Pipeline = class {
|
|
|
3658
3759
|
filter
|
|
3659
3760
|
}));
|
|
3660
3761
|
let sources = rawSources.filter((m) => m.score >= scoreThreshold);
|
|
3661
|
-
if ((
|
|
3762
|
+
if ((_g = this.config.rag) == null ? void 0 : _g.useReranking) {
|
|
3662
3763
|
sources = yield new __await(this.reranker.rerank(sources, question, topK));
|
|
3663
3764
|
} else {
|
|
3664
3765
|
sources = sources.slice(0, topK);
|
|
@@ -3704,6 +3805,7 @@ ${context}`;
|
|
|
3704
3805
|
}
|
|
3705
3806
|
/**
|
|
3706
3807
|
* Universal retrieval method combining all enabled providers.
|
|
3808
|
+
* Uses an LRU-bounded embedding cache to avoid re-embedding the same query.
|
|
3707
3809
|
*/
|
|
3708
3810
|
async retrieve(query, options) {
|
|
3709
3811
|
var _a, _b, _c;
|
|
@@ -3736,10 +3838,13 @@ ${history.map((m) => `${m.role}: ${m.content}`).join("\n")}
|
|
|
3736
3838
|
New Question: ${question}
|
|
3737
3839
|
|
|
3738
3840
|
Optimized Search Query:`;
|
|
3739
|
-
const rewrite = await this.llmProvider.chat(
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3841
|
+
const rewrite = await this.llmProvider.chat(
|
|
3842
|
+
[
|
|
3843
|
+
{ role: "system", content: "You are an assistant that optimizes search queries for RAG systems." },
|
|
3844
|
+
{ role: "user", content: prompt }
|
|
3845
|
+
],
|
|
3846
|
+
""
|
|
3847
|
+
);
|
|
3743
3848
|
return rewrite.trim() || question;
|
|
3744
3849
|
}
|
|
3745
3850
|
};
|
|
@@ -3958,8 +4063,35 @@ var DocumentParser = class {
|
|
|
3958
4063
|
};
|
|
3959
4064
|
|
|
3960
4065
|
// src/handlers/index.ts
|
|
3961
|
-
function
|
|
3962
|
-
|
|
4066
|
+
function sseFrame(payload) {
|
|
4067
|
+
return `data: ${JSON.stringify(payload)}
|
|
4068
|
+
|
|
4069
|
+
`;
|
|
4070
|
+
}
|
|
4071
|
+
function sseTextFrame(text) {
|
|
4072
|
+
return `data: ${JSON.stringify({ type: "text", text })}
|
|
4073
|
+
|
|
4074
|
+
`;
|
|
4075
|
+
}
|
|
4076
|
+
function sseMetaFrame(meta) {
|
|
4077
|
+
return `data: ${JSON.stringify(__spreadValues({ type: "metadata" }, meta != null ? meta : {}))}
|
|
4078
|
+
|
|
4079
|
+
`;
|
|
4080
|
+
}
|
|
4081
|
+
function sseErrorFrame(message) {
|
|
4082
|
+
return `data: ${JSON.stringify({ type: "error", error: message })}
|
|
4083
|
+
|
|
4084
|
+
`;
|
|
4085
|
+
}
|
|
4086
|
+
var SSE_HEADERS = {
|
|
4087
|
+
"Content-Type": "text/event-stream; charset=utf-8",
|
|
4088
|
+
"Cache-Control": "no-cache, no-transform",
|
|
4089
|
+
Connection: "keep-alive",
|
|
4090
|
+
"X-Accel-Buffering": "no"
|
|
4091
|
+
// Disable Nginx buffering for streaming
|
|
4092
|
+
};
|
|
4093
|
+
function createChatHandler(configOrPlugin) {
|
|
4094
|
+
const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
|
|
3963
4095
|
return async function POST(req) {
|
|
3964
4096
|
try {
|
|
3965
4097
|
const body = await req.json();
|
|
@@ -3975,67 +4107,64 @@ function createChatHandler(config) {
|
|
|
3975
4107
|
}
|
|
3976
4108
|
};
|
|
3977
4109
|
}
|
|
3978
|
-
function createStreamHandler(
|
|
3979
|
-
const plugin = new VectorPlugin(
|
|
4110
|
+
function createStreamHandler(configOrPlugin) {
|
|
4111
|
+
const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
|
|
3980
4112
|
return async function POST(req) {
|
|
4113
|
+
let body;
|
|
3981
4114
|
try {
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
4115
|
+
body = await req.json();
|
|
4116
|
+
} catch (e) {
|
|
4117
|
+
return new Response(JSON.stringify({ error: "Invalid JSON body" }), {
|
|
4118
|
+
status: 400,
|
|
4119
|
+
headers: { "Content-Type": "application/json" }
|
|
4120
|
+
});
|
|
4121
|
+
}
|
|
4122
|
+
const { message, history = [], namespace } = body;
|
|
4123
|
+
if (!(message == null ? void 0 : message.trim())) {
|
|
4124
|
+
return new Response(JSON.stringify({ error: "message is required" }), {
|
|
4125
|
+
status: 400,
|
|
4126
|
+
headers: { "Content-Type": "application/json" }
|
|
4127
|
+
});
|
|
4128
|
+
}
|
|
4129
|
+
const encoder = new TextEncoder();
|
|
4130
|
+
const stream = new ReadableStream({
|
|
4131
|
+
async start(controller) {
|
|
4132
|
+
const enqueue = (text) => controller.enqueue(encoder.encode(text));
|
|
4133
|
+
try {
|
|
4134
|
+
const pipelineStream = plugin.chatStream(message, history, namespace);
|
|
3987
4135
|
try {
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
} else {
|
|
3995
|
-
controller.enqueue(encoder.encode(`
|
|
3996
|
-
|
|
3997
|
-
__METADATA__${JSON.stringify(chunk)}`));
|
|
3998
|
-
}
|
|
4136
|
+
for (var iter = __forAwait(pipelineStream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
4137
|
+
const chunk = temp.value;
|
|
4138
|
+
if (typeof chunk === "string") {
|
|
4139
|
+
enqueue(sseTextFrame(chunk));
|
|
4140
|
+
} else {
|
|
4141
|
+
enqueue(sseMetaFrame(chunk));
|
|
3999
4142
|
}
|
|
4000
|
-
}
|
|
4001
|
-
|
|
4143
|
+
}
|
|
4144
|
+
} catch (temp) {
|
|
4145
|
+
error = [temp];
|
|
4146
|
+
} finally {
|
|
4147
|
+
try {
|
|
4148
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
4002
4149
|
} finally {
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
} finally {
|
|
4006
|
-
if (error)
|
|
4007
|
-
throw error[0];
|
|
4008
|
-
}
|
|
4150
|
+
if (error)
|
|
4151
|
+
throw error[0];
|
|
4009
4152
|
}
|
|
4010
|
-
controller.close();
|
|
4011
|
-
} catch (streamError) {
|
|
4012
|
-
console.error("[createStreamHandler] Stream processing error:", streamError);
|
|
4013
|
-
const errorMessage = streamError instanceof Error ? streamError.message : String(streamError);
|
|
4014
|
-
controller.enqueue(encoder.encode(`
|
|
4015
|
-
|
|
4016
|
-
__ERROR__${JSON.stringify({ error: errorMessage })}`));
|
|
4017
|
-
controller.close();
|
|
4018
4153
|
}
|
|
4154
|
+
} catch (streamError) {
|
|
4155
|
+
const errorMessage = streamError instanceof Error ? streamError.message : String(streamError);
|
|
4156
|
+
console.error("[createStreamHandler] Stream error:", streamError);
|
|
4157
|
+
enqueue(sseErrorFrame(errorMessage));
|
|
4158
|
+
} finally {
|
|
4159
|
+
controller.close();
|
|
4019
4160
|
}
|
|
4020
|
-
}
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
"Content-Type": "text/event-stream",
|
|
4024
|
-
"Cache-Control": "no-cache",
|
|
4025
|
-
"Connection": "keep-alive"
|
|
4026
|
-
}
|
|
4027
|
-
});
|
|
4028
|
-
} catch (err) {
|
|
4029
|
-
const message = err instanceof Error ? err.message : "Internal server error";
|
|
4030
|
-
return new Response(JSON.stringify({ error: message }), {
|
|
4031
|
-
status: 500,
|
|
4032
|
-
headers: { "Content-Type": "application/json" }
|
|
4033
|
-
});
|
|
4034
|
-
}
|
|
4161
|
+
}
|
|
4162
|
+
});
|
|
4163
|
+
return new Response(stream, { headers: SSE_HEADERS });
|
|
4035
4164
|
};
|
|
4036
4165
|
}
|
|
4037
|
-
function createIngestHandler(
|
|
4038
|
-
const plugin = new VectorPlugin(
|
|
4166
|
+
function createIngestHandler(configOrPlugin) {
|
|
4167
|
+
const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
|
|
4039
4168
|
return async function POST(req) {
|
|
4040
4169
|
try {
|
|
4041
4170
|
const body = await req.json();
|
|
@@ -4051,8 +4180,8 @@ function createIngestHandler(config) {
|
|
|
4051
4180
|
}
|
|
4052
4181
|
};
|
|
4053
4182
|
}
|
|
4054
|
-
function createHealthHandler(
|
|
4055
|
-
const plugin = new VectorPlugin(
|
|
4183
|
+
function createHealthHandler(configOrPlugin) {
|
|
4184
|
+
const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
|
|
4056
4185
|
return async function GET() {
|
|
4057
4186
|
try {
|
|
4058
4187
|
const health = await plugin.checkHealth();
|
|
@@ -4068,8 +4197,8 @@ function createHealthHandler(config) {
|
|
|
4068
4197
|
}
|
|
4069
4198
|
};
|
|
4070
4199
|
}
|
|
4071
|
-
function createUploadHandler(
|
|
4072
|
-
const plugin = new VectorPlugin(
|
|
4200
|
+
function createUploadHandler(configOrPlugin) {
|
|
4201
|
+
const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
|
|
4073
4202
|
return async function POST(req) {
|
|
4074
4203
|
try {
|
|
4075
4204
|
const formData = await req.formData();
|
|
@@ -4107,5 +4236,9 @@ function createUploadHandler(config) {
|
|
|
4107
4236
|
createHealthHandler,
|
|
4108
4237
|
createIngestHandler,
|
|
4109
4238
|
createStreamHandler,
|
|
4110
|
-
createUploadHandler
|
|
4239
|
+
createUploadHandler,
|
|
4240
|
+
sseErrorFrame,
|
|
4241
|
+
sseFrame,
|
|
4242
|
+
sseMetaFrame,
|
|
4243
|
+
sseTextFrame
|
|
4111
4244
|
});
|
package/dist/handlers/index.mjs
CHANGED
|
@@ -3,8 +3,12 @@ import {
|
|
|
3
3
|
createHealthHandler,
|
|
4
4
|
createIngestHandler,
|
|
5
5
|
createStreamHandler,
|
|
6
|
-
createUploadHandler
|
|
7
|
-
|
|
6
|
+
createUploadHandler,
|
|
7
|
+
sseErrorFrame,
|
|
8
|
+
sseFrame,
|
|
9
|
+
sseMetaFrame,
|
|
10
|
+
sseTextFrame
|
|
11
|
+
} from "../chunk-ZCDJSGUW.mjs";
|
|
8
12
|
import "../chunk-YLTMFW4M.mjs";
|
|
9
13
|
import "../chunk-X4TOT24V.mjs";
|
|
10
14
|
export {
|
|
@@ -12,5 +16,9 @@ export {
|
|
|
12
16
|
createHealthHandler,
|
|
13
17
|
createIngestHandler,
|
|
14
18
|
createStreamHandler,
|
|
15
|
-
createUploadHandler
|
|
19
|
+
createUploadHandler,
|
|
20
|
+
sseErrorFrame,
|
|
21
|
+
sseFrame,
|
|
22
|
+
sseMetaFrame,
|
|
23
|
+
sseTextFrame
|
|
16
24
|
};
|