@retrivora-ai/rag-engine 1.0.0 → 1.0.2
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/{ChromaDBProvider-APQVJ5F7.mjs → ChromaDBProvider-MIDOR4FW.mjs} +2 -2
- package/dist/{MilvusProvider-35US67MS.mjs → MilvusProvider-U7SKC27V.mjs} +2 -2
- package/dist/{MongoDBProvider-COVYZDP6.mjs → MongoDBProvider-BO2Y5DRR.mjs} +2 -2
- package/dist/{PineconeProvider-AWFJQDZL.mjs → PineconeProvider-QZNRKTN2.mjs} +2 -2
- package/dist/{PostgreSQLProvider-IEYRJ7XJ.mjs → PostgreSQLProvider-BMOETDZA.mjs} +1 -1
- package/dist/{QdrantProvider-M6TQYZRO.mjs → QdrantProvider-YNUNEOZH.mjs} +2 -2
- package/dist/{RedisProvider-3G5PBLZ4.mjs → RedisProvider-SR65SCKV.mjs} +2 -2
- package/dist/{SimpleGraphProvider-UK7DJW37.mjs → SimpleGraphProvider-SLOXO4M7.mjs} +1 -1
- package/dist/{UniversalVectorProvider-FYQ3B2PW.mjs → UniversalVectorProvider-IN67OS56.mjs} +3 -3
- package/dist/{WeaviateProvider-ITHO36IL.mjs → WeaviateProvider-5FWDFITI.mjs} +2 -2
- package/dist/{chunk-4A47RCG2.mjs → chunk-3DSHW676.mjs} +1 -1
- package/dist/{chunk-NXUCKY5L.mjs → chunk-5YGUXK7Z.mjs} +1 -1
- package/dist/{chunk-7SOSCZGS.mjs → chunk-73I6VWU3.mjs} +2 -2
- package/dist/{chunk-WGSZNY3X.mjs → chunk-CFVEZTBJ.mjs} +1 -1
- package/dist/{chunk-U6KHVZLF.mjs → chunk-LR3VMDVK.mjs} +2 -2
- package/dist/{chunk-OOQXNLXD.mjs → chunk-M6JSPGAR.mjs} +1 -1
- package/dist/{chunk-P4HAQ7KB.mjs → chunk-OJNAKSQ2.mjs} +90 -34
- package/dist/{chunk-TYHTZIDP.mjs → chunk-U55XRW3U.mjs} +1 -1
- package/dist/{chunk-ZNBKHNJ4.mjs → chunk-VUQJVIJT.mjs} +1 -1
- package/dist/{chunk-QMIKLALV.mjs → chunk-X4TOT24V.mjs} +32 -0
- package/dist/{chunk-67AJ6SMD.mjs → chunk-YLTMFW4M.mjs} +1 -1
- package/dist/handlers/index.d.mts +1 -1
- package/dist/handlers/index.d.ts +1 -1
- package/dist/handlers/index.js +109 -22
- package/dist/handlers/index.mjs +5 -3
- package/dist/{index-CrGMwXfO.d.ts → index-B2mutkgp.d.ts} +5 -1
- package/dist/{index-v669iV-k.d.mts → index-Bjy0es5a.d.mts} +5 -1
- package/dist/index.d.mts +13 -7
- package/dist/index.d.ts +13 -7
- package/dist/index.js +325 -380
- package/dist/index.mjs +315 -370
- package/dist/server.d.mts +7 -22
- package/dist/server.d.ts +7 -22
- package/dist/server.js +48 -22
- package/dist/server.mjs +11 -11
- package/package.json +1 -1
- package/src/components/ChatWindow.tsx +4 -3
- package/src/components/MessageBubble.tsx +5 -2
- package/src/core/Pipeline.ts +1 -0
- package/src/core/VectorPlugin.ts +13 -22
- package/src/handlers/index.ts +53 -0
- package/src/hooks/useRagChat.ts +79 -15
- package/src/providers/vectordb/MongoDBProvider.ts +1 -1
- package/src/rag/EntityExtractor.ts +3 -0
package/dist/server.d.mts
CHANGED
|
@@ -2,8 +2,8 @@ import { e as VectorDBConfig, L as LLMConfig, E as EmbeddingConfig, c as RagConf
|
|
|
2
2
|
export { R as RAGConfig, U as UIConfig } from './RagConfig-DRJO4hGU.mjs';
|
|
3
3
|
import { C as ChatMessage, I as ILLMProvider, a as ChatOptions, E as EmbedOptions } from './DocumentChunker-C-sCZPhi.mjs';
|
|
4
4
|
export { b as Chunk, c as ChunkOptions, D as DocumentChunker } from './DocumentChunker-C-sCZPhi.mjs';
|
|
5
|
-
import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-
|
|
6
|
-
export { C as ConfigValidator, V as ValidationError, c as createChatHandler, b as createHealthHandler, d as createIngestHandler, e as createUploadHandler } from './index-
|
|
5
|
+
import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-Bjy0es5a.mjs';
|
|
6
|
+
export { C as ConfigValidator, V as ValidationError, c as createChatHandler, b as createHealthHandler, d as createIngestHandler, e as createUploadHandler } from './index-Bjy0es5a.mjs';
|
|
7
7
|
import 'next/server';
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -111,26 +111,7 @@ declare class ProviderHealthCheck {
|
|
|
111
111
|
declare class VectorPlugin {
|
|
112
112
|
private config;
|
|
113
113
|
private pipeline;
|
|
114
|
-
|
|
115
|
-
* Initializes the plugin with the host configuration.
|
|
116
|
-
* @param hostConfig - Configuration object passed from the host application.
|
|
117
|
-
* @throws Error if configuration is invalid or providers are unhealthy
|
|
118
|
-
*
|
|
119
|
-
* @example
|
|
120
|
-
* const plugin = new VectorPlugin({
|
|
121
|
-
* projectId: 'my-app',
|
|
122
|
-
* vectorDb: {
|
|
123
|
-
* provider: 'pinecone',
|
|
124
|
-
* indexName: 'my-index',
|
|
125
|
-
* options: { apiKey: process.env.PINECONE_API_KEY }
|
|
126
|
-
* },
|
|
127
|
-
* llm: {
|
|
128
|
-
* provider: 'openai',
|
|
129
|
-
* model: 'gpt-4o',
|
|
130
|
-
* apiKey: process.env.OPENAI_API_KEY
|
|
131
|
-
* }
|
|
132
|
-
* });
|
|
133
|
-
*/
|
|
114
|
+
private validationPromise;
|
|
134
115
|
constructor(hostConfig?: Partial<RagConfig>);
|
|
135
116
|
/**
|
|
136
117
|
* Get the current resolved configuration.
|
|
@@ -152,6 +133,10 @@ declare class VectorPlugin {
|
|
|
152
133
|
* Run a chat query.
|
|
153
134
|
*/
|
|
154
135
|
chat(message: string, history?: ChatMessage[], namespace?: string): Promise<ChatResponse>;
|
|
136
|
+
/**
|
|
137
|
+
* Run a streaming chat query.
|
|
138
|
+
*/
|
|
139
|
+
chatStream(message: string, history?: ChatMessage[], namespace?: string): AsyncGenerator<string | ChatResponse, void, any>;
|
|
155
140
|
/**
|
|
156
141
|
* Ingest documents into the vector database.
|
|
157
142
|
*/
|
package/dist/server.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { e as VectorDBConfig, L as LLMConfig, E as EmbeddingConfig, c as RagConf
|
|
|
2
2
|
export { R as RAGConfig, U as UIConfig } from './RagConfig-DRJO4hGU.js';
|
|
3
3
|
import { C as ChatMessage, I as ILLMProvider, a as ChatOptions, E as EmbedOptions } from './DocumentChunker-C-sCZPhi.js';
|
|
4
4
|
export { b as Chunk, c as ChunkOptions, D as DocumentChunker } from './DocumentChunker-C-sCZPhi.js';
|
|
5
|
-
import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-
|
|
6
|
-
export { C as ConfigValidator, V as ValidationError, c as createChatHandler, b as createHealthHandler, d as createIngestHandler, e as createUploadHandler } from './index-
|
|
5
|
+
import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-B2mutkgp.js';
|
|
6
|
+
export { C as ConfigValidator, V as ValidationError, c as createChatHandler, b as createHealthHandler, d as createIngestHandler, e as createUploadHandler } from './index-B2mutkgp.js';
|
|
7
7
|
import 'next/server';
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -111,26 +111,7 @@ declare class ProviderHealthCheck {
|
|
|
111
111
|
declare class VectorPlugin {
|
|
112
112
|
private config;
|
|
113
113
|
private pipeline;
|
|
114
|
-
|
|
115
|
-
* Initializes the plugin with the host configuration.
|
|
116
|
-
* @param hostConfig - Configuration object passed from the host application.
|
|
117
|
-
* @throws Error if configuration is invalid or providers are unhealthy
|
|
118
|
-
*
|
|
119
|
-
* @example
|
|
120
|
-
* const plugin = new VectorPlugin({
|
|
121
|
-
* projectId: 'my-app',
|
|
122
|
-
* vectorDb: {
|
|
123
|
-
* provider: 'pinecone',
|
|
124
|
-
* indexName: 'my-index',
|
|
125
|
-
* options: { apiKey: process.env.PINECONE_API_KEY }
|
|
126
|
-
* },
|
|
127
|
-
* llm: {
|
|
128
|
-
* provider: 'openai',
|
|
129
|
-
* model: 'gpt-4o',
|
|
130
|
-
* apiKey: process.env.OPENAI_API_KEY
|
|
131
|
-
* }
|
|
132
|
-
* });
|
|
133
|
-
*/
|
|
114
|
+
private validationPromise;
|
|
134
115
|
constructor(hostConfig?: Partial<RagConfig>);
|
|
135
116
|
/**
|
|
136
117
|
* Get the current resolved configuration.
|
|
@@ -152,6 +133,10 @@ declare class VectorPlugin {
|
|
|
152
133
|
* Run a chat query.
|
|
153
134
|
*/
|
|
154
135
|
chat(message: string, history?: ChatMessage[], namespace?: string): Promise<ChatResponse>;
|
|
136
|
+
/**
|
|
137
|
+
* Run a streaming chat query.
|
|
138
|
+
*/
|
|
139
|
+
chatStream(message: string, history?: ChatMessage[], namespace?: string): AsyncGenerator<string | ChatResponse, void, any>;
|
|
155
140
|
/**
|
|
156
141
|
* Ingest documents into the vector database.
|
|
157
142
|
*/
|
package/dist/server.js
CHANGED
|
@@ -10,6 +10,9 @@ var __getProtoOf = Object.getPrototypeOf;
|
|
|
10
10
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
11
11
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
12
12
|
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : /* @__PURE__ */ Symbol.for("Symbol." + name);
|
|
13
|
+
var __typeError = (msg) => {
|
|
14
|
+
throw TypeError(msg);
|
|
15
|
+
};
|
|
13
16
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
14
17
|
var __spreadValues = (a, b) => {
|
|
15
18
|
for (var prop in b || (b = {}))
|
|
@@ -74,6 +77,34 @@ var __asyncGenerator = (__this, __arguments, generator) => {
|
|
|
74
77
|
}, method = (k, call, wait, clear) => it[k] = (x) => (call = new Promise((yes, no, run) => (run = () => resume(k, x, yes, no), q ? q.then(run) : run())), clear = () => q === wait && (q = 0), q = wait = call.then(clear, clear), call), q, it = {};
|
|
75
78
|
return generator = generator.apply(__this, __arguments), it[__knownSymbol("asyncIterator")] = () => it, method("next"), method("throw"), method("return"), it;
|
|
76
79
|
};
|
|
80
|
+
var __yieldStar = (value) => {
|
|
81
|
+
var obj = value[__knownSymbol("asyncIterator")], isAwait = false, method, it = {};
|
|
82
|
+
if (obj == null) {
|
|
83
|
+
obj = value[__knownSymbol("iterator")]();
|
|
84
|
+
method = (k) => it[k] = (x) => obj[k](x);
|
|
85
|
+
} else {
|
|
86
|
+
obj = obj.call(value);
|
|
87
|
+
method = (k) => it[k] = (v) => {
|
|
88
|
+
if (isAwait) {
|
|
89
|
+
isAwait = false;
|
|
90
|
+
if (k === "throw") throw v;
|
|
91
|
+
return v;
|
|
92
|
+
}
|
|
93
|
+
isAwait = true;
|
|
94
|
+
return {
|
|
95
|
+
done: false,
|
|
96
|
+
value: new __await(new Promise((resolve) => {
|
|
97
|
+
var x = obj[k](v);
|
|
98
|
+
if (!(x instanceof Object)) __typeError("Object expected");
|
|
99
|
+
resolve(x);
|
|
100
|
+
}), 1)
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
return it[__knownSymbol("iterator")] = () => it, method("next"), "throw" in obj ? method("throw") : it.throw = (x) => {
|
|
105
|
+
throw x;
|
|
106
|
+
}, "return" in obj && method("return"), it;
|
|
107
|
+
};
|
|
77
108
|
var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")]) ? it.call(obj) : (obj = obj[__knownSymbol("iterator")](), it = {}, method = (key, fn) => (fn = obj[key]) && (it[key] = (arg) => new Promise((yes, no, done) => (arg = fn.call(obj, arg), done = arg.done, Promise.resolve(arg.value).then((value) => yes({ value, done }), no)))), method("next"), method("return"), it);
|
|
78
109
|
|
|
79
110
|
// src/utils/templateUtils.ts
|
|
@@ -527,7 +558,7 @@ var init_MongoDBProvider = __esm({
|
|
|
527
558
|
if (!opts.uri || !opts.database || !opts.collection) {
|
|
528
559
|
throw new Error("[MongoDBProvider] options uri, database, and collection are required.");
|
|
529
560
|
}
|
|
530
|
-
this.client = new import_mongodb.MongoClient(opts.uri);
|
|
561
|
+
this.client = new import_mongodb.MongoClient(opts.uri, { serverSelectionTimeoutMS: 5e3 });
|
|
531
562
|
this.dbName = opts.database;
|
|
532
563
|
this.collectionName = opts.collection;
|
|
533
564
|
this.embeddingKey = opts.embeddingKey || "embedding";
|
|
@@ -2908,6 +2939,9 @@ Extract entities and relationships from the following text.
|
|
|
2908
2939
|
Format the output as JSON with two keys: "nodes" (array of {id, label, properties}) and "edges" (array of {source, target, type, properties}).
|
|
2909
2940
|
Use the same ID for the same entity.
|
|
2910
2941
|
|
|
2942
|
+
IMPORTANT: Ensure all property values are valid JSON types (strings, numbers, booleans, or null).
|
|
2943
|
+
DO NOT include mathematical expressions like "4.5/5" as numbers; use strings instead.
|
|
2944
|
+
|
|
2911
2945
|
Text:
|
|
2912
2946
|
"${text}"
|
|
2913
2947
|
|
|
@@ -3488,6 +3522,7 @@ var Pipeline = class {
|
|
|
3488
3522
|
async initialize() {
|
|
3489
3523
|
var _a;
|
|
3490
3524
|
if (this.initialised) return;
|
|
3525
|
+
console.log(`[Pipeline] Initializing with provider: ${this.config.vectorDb.provider}...`);
|
|
3491
3526
|
this.vectorDB = await ProviderRegistry.createVectorProvider(this.config.vectorDb);
|
|
3492
3527
|
const { llmProvider, embeddingProvider } = await EmbeddingStrategyResolver.resolve(
|
|
3493
3528
|
this.config.llm,
|
|
@@ -3872,29 +3907,9 @@ var ProviderHealthCheck = class {
|
|
|
3872
3907
|
|
|
3873
3908
|
// src/core/VectorPlugin.ts
|
|
3874
3909
|
var VectorPlugin = class {
|
|
3875
|
-
/**
|
|
3876
|
-
* Initializes the plugin with the host configuration.
|
|
3877
|
-
* @param hostConfig - Configuration object passed from the host application.
|
|
3878
|
-
* @throws Error if configuration is invalid or providers are unhealthy
|
|
3879
|
-
*
|
|
3880
|
-
* @example
|
|
3881
|
-
* const plugin = new VectorPlugin({
|
|
3882
|
-
* projectId: 'my-app',
|
|
3883
|
-
* vectorDb: {
|
|
3884
|
-
* provider: 'pinecone',
|
|
3885
|
-
* indexName: 'my-index',
|
|
3886
|
-
* options: { apiKey: process.env.PINECONE_API_KEY }
|
|
3887
|
-
* },
|
|
3888
|
-
* llm: {
|
|
3889
|
-
* provider: 'openai',
|
|
3890
|
-
* model: 'gpt-4o',
|
|
3891
|
-
* apiKey: process.env.OPENAI_API_KEY
|
|
3892
|
-
* }
|
|
3893
|
-
* });
|
|
3894
|
-
*/
|
|
3895
3910
|
constructor(hostConfig) {
|
|
3896
3911
|
this.config = ConfigResolver.resolve(hostConfig);
|
|
3897
|
-
ConfigValidator.validateAndThrow(this.config);
|
|
3912
|
+
this.validationPromise = ConfigValidator.validateAndThrow(this.config);
|
|
3898
3913
|
this.pipeline = new Pipeline(this.config);
|
|
3899
3914
|
}
|
|
3900
3915
|
/**
|
|
@@ -3920,12 +3935,23 @@ var VectorPlugin = class {
|
|
|
3920
3935
|
* Run a chat query.
|
|
3921
3936
|
*/
|
|
3922
3937
|
async chat(message, history = [], namespace) {
|
|
3938
|
+
await this.validationPromise;
|
|
3923
3939
|
return this.pipeline.ask(message, history, namespace);
|
|
3924
3940
|
}
|
|
3941
|
+
/**
|
|
3942
|
+
* Run a streaming chat query.
|
|
3943
|
+
*/
|
|
3944
|
+
chatStream(_0) {
|
|
3945
|
+
return __asyncGenerator(this, arguments, function* (message, history = [], namespace) {
|
|
3946
|
+
yield new __await(this.validationPromise);
|
|
3947
|
+
yield* __yieldStar(this.pipeline.askStream(message, history, namespace));
|
|
3948
|
+
});
|
|
3949
|
+
}
|
|
3925
3950
|
/**
|
|
3926
3951
|
* Ingest documents into the vector database.
|
|
3927
3952
|
*/
|
|
3928
3953
|
async ingest(documents, namespace) {
|
|
3954
|
+
await this.validationPromise;
|
|
3929
3955
|
return this.pipeline.ingest(documents, namespace);
|
|
3930
3956
|
}
|
|
3931
3957
|
};
|
package/dist/server.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ChromaDBProvider
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-CFVEZTBJ.mjs";
|
|
4
4
|
import {
|
|
5
5
|
RedisProvider
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-5YGUXK7Z.mjs";
|
|
7
7
|
import {
|
|
8
8
|
WeaviateProvider
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-M6JSPGAR.mjs";
|
|
10
10
|
import {
|
|
11
11
|
UniversalVectorProvider
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-LR3VMDVK.mjs";
|
|
13
13
|
import {
|
|
14
14
|
AnthropicProvider,
|
|
15
15
|
BatchProcessor,
|
|
@@ -34,23 +34,23 @@ import {
|
|
|
34
34
|
createIngestHandler,
|
|
35
35
|
createUploadHandler,
|
|
36
36
|
getRagConfig
|
|
37
|
-
} from "./chunk-
|
|
38
|
-
import "./chunk-
|
|
37
|
+
} from "./chunk-OJNAKSQ2.mjs";
|
|
38
|
+
import "./chunk-YLTMFW4M.mjs";
|
|
39
39
|
import {
|
|
40
40
|
PineconeProvider
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-VUQJVIJT.mjs";
|
|
42
42
|
import {
|
|
43
43
|
PostgreSQLProvider
|
|
44
44
|
} from "./chunk-FLOSGE6A.mjs";
|
|
45
45
|
import {
|
|
46
46
|
MongoDBProvider
|
|
47
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-73I6VWU3.mjs";
|
|
48
48
|
import {
|
|
49
49
|
MilvusProvider
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-U55XRW3U.mjs";
|
|
51
51
|
import {
|
|
52
52
|
QdrantProvider
|
|
53
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-3DSHW676.mjs";
|
|
54
54
|
import {
|
|
55
55
|
BaseVectorProvider
|
|
56
56
|
} from "./chunk-IMP6FUCY.mjs";
|
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
__objRest,
|
|
59
59
|
__spreadProps,
|
|
60
60
|
__spreadValues
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-X4TOT24V.mjs";
|
|
62
62
|
|
|
63
63
|
// src/config/ConfigBuilder.ts
|
|
64
64
|
var ConfigBuilder = class {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retrivora-ai/rag-engine",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Retrivora AI is a plug-and-play AI engine for RAG chat experiences — generic vector DB + LLM provider, embeddable or standalone.",
|
|
5
5
|
"author": "Abhinav Alkuchi",
|
|
6
6
|
"license": "MIT",
|
|
@@ -170,19 +170,20 @@ export function ChatWindow({ className = '', style, onClose, showClose = false }
|
|
|
170
170
|
</div>
|
|
171
171
|
</div>
|
|
172
172
|
) : (
|
|
173
|
-
messages.map((msg) => (
|
|
173
|
+
messages.map((msg, index) => (
|
|
174
174
|
<MessageBubble
|
|
175
175
|
key={msg.id}
|
|
176
176
|
message={msg}
|
|
177
177
|
sources={msg.sources}
|
|
178
|
+
isStreaming={isLoading && index === messages.length - 1 && msg.role === 'assistant'}
|
|
178
179
|
primaryColor={ui.primaryColor}
|
|
179
180
|
accentColor={ui.accentColor}
|
|
180
181
|
/>
|
|
181
182
|
))
|
|
182
183
|
)}
|
|
183
184
|
|
|
184
|
-
{/* Typing indicator */}
|
|
185
|
-
{isLoading && (
|
|
185
|
+
{/* Typing indicator (only if assistant hasn't started replying yet) */}
|
|
186
|
+
{isLoading && messages[messages.length - 1]?.role !== 'assistant' && (
|
|
186
187
|
<MessageBubble
|
|
187
188
|
message={{ role: 'assistant', content: '' }}
|
|
188
189
|
isStreaming
|
|
@@ -55,8 +55,8 @@ export function MessageBubble({
|
|
|
55
55
|
: {}
|
|
56
56
|
}
|
|
57
57
|
>
|
|
58
|
-
{isStreaming ? (
|
|
59
|
-
<span className="flex items-center gap-1">
|
|
58
|
+
{isStreaming && !message.content ? (
|
|
59
|
+
<span className="flex items-center gap-1 py-1">
|
|
60
60
|
<span className="w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:0ms]" />
|
|
61
61
|
<span className="w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:150ms]" />
|
|
62
62
|
<span className="w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" />
|
|
@@ -66,6 +66,9 @@ export function MessageBubble({
|
|
|
66
66
|
<ReactMarkdown remarkPlugins={[remarkGfm]}>
|
|
67
67
|
{message.content}
|
|
68
68
|
</ReactMarkdown>
|
|
69
|
+
{isStreaming && message.content && (
|
|
70
|
+
<span className="inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" />
|
|
71
|
+
)}
|
|
69
72
|
</div>
|
|
70
73
|
)}
|
|
71
74
|
</div>
|
package/src/core/Pipeline.ts
CHANGED
|
@@ -50,6 +50,7 @@ export class Pipeline {
|
|
|
50
50
|
async initialize(): Promise<void> {
|
|
51
51
|
if (this.initialised) return;
|
|
52
52
|
|
|
53
|
+
console.log(`[Pipeline] Initializing with provider: ${this.config.vectorDb.provider}...`);
|
|
53
54
|
// Resolve vector DB provider
|
|
54
55
|
this.vectorDB = await ProviderRegistry.createVectorProvider(this.config.vectorDb);
|
|
55
56
|
|
package/src/core/VectorPlugin.ts
CHANGED
|
@@ -20,32 +20,13 @@ import { ChatMessage } from '../llm/ILLMProvider';
|
|
|
20
20
|
export class VectorPlugin {
|
|
21
21
|
private config: RagConfig;
|
|
22
22
|
private pipeline: Pipeline;
|
|
23
|
+
private validationPromise: Promise<void>;
|
|
23
24
|
|
|
24
|
-
/**
|
|
25
|
-
* Initializes the plugin with the host configuration.
|
|
26
|
-
* @param hostConfig - Configuration object passed from the host application.
|
|
27
|
-
* @throws Error if configuration is invalid or providers are unhealthy
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* const plugin = new VectorPlugin({
|
|
31
|
-
* projectId: 'my-app',
|
|
32
|
-
* vectorDb: {
|
|
33
|
-
* provider: 'pinecone',
|
|
34
|
-
* indexName: 'my-index',
|
|
35
|
-
* options: { apiKey: process.env.PINECONE_API_KEY }
|
|
36
|
-
* },
|
|
37
|
-
* llm: {
|
|
38
|
-
* provider: 'openai',
|
|
39
|
-
* model: 'gpt-4o',
|
|
40
|
-
* apiKey: process.env.OPENAI_API_KEY
|
|
41
|
-
* }
|
|
42
|
-
* });
|
|
43
|
-
*/
|
|
44
25
|
constructor(hostConfig?: Partial<RagConfig>) {
|
|
45
26
|
this.config = ConfigResolver.resolve(hostConfig);
|
|
46
27
|
|
|
47
|
-
//
|
|
48
|
-
ConfigValidator.validateAndThrow(this.config);
|
|
28
|
+
// Start validation early
|
|
29
|
+
this.validationPromise = ConfigValidator.validateAndThrow(this.config);
|
|
49
30
|
|
|
50
31
|
this.pipeline = new Pipeline(this.config);
|
|
51
32
|
}
|
|
@@ -80,13 +61,23 @@ export class VectorPlugin {
|
|
|
80
61
|
* Run a chat query.
|
|
81
62
|
*/
|
|
82
63
|
async chat(message: string, history: ChatMessage[] = [], namespace?: string): Promise<ChatResponse> {
|
|
64
|
+
await this.validationPromise;
|
|
83
65
|
return this.pipeline.ask(message, history, namespace);
|
|
84
66
|
}
|
|
85
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Run a streaming chat query.
|
|
70
|
+
*/
|
|
71
|
+
async *chatStream(message: string, history: ChatMessage[] = [], namespace?: string) {
|
|
72
|
+
await this.validationPromise;
|
|
73
|
+
yield* this.pipeline.askStream(message, history, namespace);
|
|
74
|
+
}
|
|
75
|
+
|
|
86
76
|
/**
|
|
87
77
|
* Ingest documents into the vector database.
|
|
88
78
|
*/
|
|
89
79
|
async ingest(documents: IngestDocument[], namespace?: string): Promise<Array<{ docId: string | number; chunksIngested: number }>> {
|
|
80
|
+
await this.validationPromise;
|
|
90
81
|
return this.pipeline.ingest(documents, namespace);
|
|
91
82
|
}
|
|
92
83
|
|
package/src/handlers/index.ts
CHANGED
|
@@ -32,6 +32,59 @@ export function createChatHandler(config?: Partial<RagConfig>) {
|
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* createStreamHandler — factory that returns a streaming Next.js App Router POST handler
|
|
37
|
+
*/
|
|
38
|
+
export function createStreamHandler(config?: Partial<RagConfig>) {
|
|
39
|
+
const plugin = new VectorPlugin(config);
|
|
40
|
+
|
|
41
|
+
return async function POST(req: NextRequest) {
|
|
42
|
+
try {
|
|
43
|
+
const body = await req.json();
|
|
44
|
+
const { message, history = [], namespace } = body;
|
|
45
|
+
|
|
46
|
+
const encoder = new TextEncoder();
|
|
47
|
+
const stream = new ReadableStream({
|
|
48
|
+
async start(controller) {
|
|
49
|
+
try {
|
|
50
|
+
const pipelineStream = plugin.chatStream(message, history, namespace);
|
|
51
|
+
|
|
52
|
+
for await (const chunk of pipelineStream) {
|
|
53
|
+
if (typeof chunk === 'string') {
|
|
54
|
+
controller.enqueue(encoder.encode(chunk));
|
|
55
|
+
} else {
|
|
56
|
+
// Yield metadata/sources at the end
|
|
57
|
+
controller.enqueue(encoder.encode(`\n\n__METADATA__${JSON.stringify(chunk)}`));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
controller.close();
|
|
61
|
+
} catch (streamError) {
|
|
62
|
+
console.error('[createStreamHandler] Stream processing error:', streamError);
|
|
63
|
+
const errorMessage = streamError instanceof Error ? streamError.message : String(streamError);
|
|
64
|
+
controller.enqueue(encoder.encode(`\n\n__ERROR__${JSON.stringify({ error: errorMessage })}`));
|
|
65
|
+
controller.close();
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
return new Response(stream, {
|
|
71
|
+
headers: {
|
|
72
|
+
'Content-Type': 'text/event-stream',
|
|
73
|
+
'Cache-Control': 'no-cache',
|
|
74
|
+
'Connection': 'keep-alive',
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
} catch (err) {
|
|
78
|
+
const message = err instanceof Error ? err.message : 'Internal server error';
|
|
79
|
+
return new Response(JSON.stringify({ error: message }), {
|
|
80
|
+
status: 500,
|
|
81
|
+
headers: { 'Content-Type': 'application/json' },
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
35
88
|
/**
|
|
36
89
|
* createIngestHandler — factory for the document ingestion endpoint.
|
|
37
90
|
*/
|
package/src/hooks/useRagChat.ts
CHANGED
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { useState, useCallback, useRef, useEffect } from 'react';
|
|
17
|
-
import axios from 'axios';
|
|
18
17
|
import { VectorMatch } from '@/types';
|
|
19
18
|
import { useStoredMessages } from './useStoredMessages';
|
|
20
19
|
|
|
@@ -111,26 +110,91 @@ export function useRagChat(
|
|
|
111
110
|
try {
|
|
112
111
|
const history = messagesRef.current.map(({ role, content }) => ({ role, content }));
|
|
113
112
|
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
113
|
+
const response = await fetch(apiUrl, {
|
|
114
|
+
method: 'POST',
|
|
115
|
+
headers: { 'Content-Type': 'application/json' },
|
|
116
|
+
body: JSON.stringify({
|
|
117
|
+
message: trimmed,
|
|
118
|
+
history,
|
|
119
|
+
namespace: namespace ?? projectId,
|
|
120
|
+
}),
|
|
118
121
|
});
|
|
119
122
|
|
|
120
|
-
|
|
121
|
-
|
|
123
|
+
if (!response.ok) {
|
|
124
|
+
const errorData = await response.json().catch(() => ({}));
|
|
125
|
+
throw new Error(errorData.error || `Server returned ${response.status}`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (!response.body) {
|
|
129
|
+
throw new Error('No response body received from server');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const reader = response.body.getReader();
|
|
133
|
+
const decoder = new TextDecoder();
|
|
134
|
+
let assistantContent = '';
|
|
135
|
+
let sources: VectorMatch[] = [];
|
|
136
|
+
|
|
137
|
+
// Add a placeholder assistant message that we will update
|
|
138
|
+
const assistantMessageId = `assistant_${Date.now()}`;
|
|
139
|
+
setMessages((prev) => [
|
|
140
|
+
...prev,
|
|
141
|
+
{
|
|
142
|
+
id: assistantMessageId,
|
|
143
|
+
role: 'assistant',
|
|
144
|
+
content: '',
|
|
145
|
+
createdAt: new Date().toISOString(),
|
|
146
|
+
},
|
|
147
|
+
]);
|
|
148
|
+
|
|
149
|
+
while (true) {
|
|
150
|
+
const { done, value } = await reader.read();
|
|
151
|
+
if (done) break;
|
|
152
|
+
|
|
153
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
154
|
+
|
|
155
|
+
// Handle protocol tokens
|
|
156
|
+
if (chunk.includes('__METADATA__')) {
|
|
157
|
+
const [text, metadataStr] = chunk.split('__METADATA__');
|
|
158
|
+
if (text) assistantContent += text;
|
|
159
|
+
try {
|
|
160
|
+
const meta = JSON.parse(metadataStr);
|
|
161
|
+
sources = meta.sources || [];
|
|
162
|
+
} catch {
|
|
163
|
+
console.warn('[useRagChat] Failed to parse metadata');
|
|
164
|
+
}
|
|
165
|
+
} else if (chunk.includes('__ERROR__')) {
|
|
166
|
+
const [text, errorStr] = chunk.split('__ERROR__');
|
|
167
|
+
if (text) assistantContent += text;
|
|
168
|
+
try {
|
|
169
|
+
const err = JSON.parse(errorStr);
|
|
170
|
+
setError(err.error || 'Stream error');
|
|
171
|
+
} catch {
|
|
172
|
+
setError('An error occurred during streaming');
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
assistantContent += chunk;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Update the specific message
|
|
179
|
+
setMessages((prev) =>
|
|
180
|
+
prev.map((msg) =>
|
|
181
|
+
msg.id === assistantMessageId
|
|
182
|
+
? { ...msg, content: assistantContent, sources: sources.length > 0 ? sources : msg.sources }
|
|
183
|
+
: msg
|
|
184
|
+
)
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const finalAssistantMessage: RagMessage = {
|
|
189
|
+
id: assistantMessageId,
|
|
122
190
|
role: 'assistant',
|
|
123
|
-
content:
|
|
124
|
-
sources:
|
|
191
|
+
content: assistantContent,
|
|
192
|
+
sources: sources.length > 0 ? sources : undefined,
|
|
125
193
|
createdAt: new Date().toISOString(),
|
|
126
194
|
};
|
|
127
|
-
|
|
128
|
-
setMessages((prev) => [...prev, assistantMessage]);
|
|
129
|
-
onReply?.(assistantMessage);
|
|
195
|
+
onReply?.(finalAssistantMessage);
|
|
130
196
|
} catch (err) {
|
|
131
|
-
const msg =
|
|
132
|
-
? (err.response?.data?.error ?? err.message)
|
|
133
|
-
: 'Something went wrong. Please try again.';
|
|
197
|
+
const msg = err instanceof Error ? err.message : 'Something went wrong. Please try again.';
|
|
134
198
|
setError(msg);
|
|
135
199
|
onError?.(msg);
|
|
136
200
|
} finally {
|
|
@@ -25,7 +25,7 @@ export class MongoDBProvider extends BaseVectorProvider {
|
|
|
25
25
|
if (!opts.uri || !opts.database || !opts.collection) {
|
|
26
26
|
throw new Error('[MongoDBProvider] options uri, database, and collection are required.');
|
|
27
27
|
}
|
|
28
|
-
this.client = new MongoClient(opts.uri as string);
|
|
28
|
+
this.client = new MongoClient(opts.uri as string, { serverSelectionTimeoutMS: 5000 });
|
|
29
29
|
this.dbName = opts.database as string;
|
|
30
30
|
this.collectionName = opts.collection as string;
|
|
31
31
|
this.embeddingKey = (opts.embeddingKey as string) || 'embedding';
|
|
@@ -20,6 +20,9 @@ Extract entities and relationships from the following text.
|
|
|
20
20
|
Format the output as JSON with two keys: "nodes" (array of {id, label, properties}) and "edges" (array of {source, target, type, properties}).
|
|
21
21
|
Use the same ID for the same entity.
|
|
22
22
|
|
|
23
|
+
IMPORTANT: Ensure all property values are valid JSON types (strings, numbers, booleans, or null).
|
|
24
|
+
DO NOT include mathematical expressions like "4.5/5" as numbers; use strings instead.
|
|
25
|
+
|
|
23
26
|
Text:
|
|
24
27
|
"${text}"
|
|
25
28
|
|