@retrivora-ai/rag-engine 2.0.5 → 2.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/handlers/index.js +113 -28
- package/dist/handlers/index.mjs +113 -28
- package/dist/server.js +113 -28
- package/dist/server.mjs +113 -28
- package/package.json +1 -1
- package/src/core/DatabaseStorage.ts +26 -4
- package/src/core/Pipeline.ts +10 -5
- package/src/llm/providers/UniversalLLMAdapter.ts +82 -12
package/dist/handlers/index.js
CHANGED
|
@@ -3907,7 +3907,7 @@ var UniversalLLMAdapter = class {
|
|
|
3907
3907
|
});
|
|
3908
3908
|
}
|
|
3909
3909
|
async chat(messages, context) {
|
|
3910
|
-
var _a2, _b;
|
|
3910
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3911
3911
|
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3912
3912
|
const formattedMessages = [
|
|
3913
3913
|
{ role: "system", content: `${this.systemPrompt}
|
|
@@ -3932,8 +3932,26 @@ ${context != null ? context : "None"}` },
|
|
|
3932
3932
|
temperature: this.temperature
|
|
3933
3933
|
};
|
|
3934
3934
|
}
|
|
3935
|
+
const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
|
|
3936
|
+
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
3937
|
+
try {
|
|
3938
|
+
const _g2 = globalThis;
|
|
3939
|
+
if (typeof _g2.__retrivoraDispatchChat === "function") {
|
|
3940
|
+
const res = await _g2.__retrivoraDispatchChat({
|
|
3941
|
+
model: this.model,
|
|
3942
|
+
messages: formattedMessages,
|
|
3943
|
+
max_tokens: this.maxTokens,
|
|
3944
|
+
temperature: this.temperature
|
|
3945
|
+
}, this.apiKey);
|
|
3946
|
+
if ((_e = (_d = (_c = (_b = res == null ? void 0 : res.response) == null ? void 0 : _b.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) {
|
|
3947
|
+
return res.response.choices[0].message.content;
|
|
3948
|
+
}
|
|
3949
|
+
}
|
|
3950
|
+
} catch (e) {
|
|
3951
|
+
}
|
|
3952
|
+
}
|
|
3935
3953
|
const { data } = await this.http.post(path2, payload);
|
|
3936
|
-
const extractPath = (
|
|
3954
|
+
const extractPath = (_f = this.opts.responseExtractPath) != null ? _f : "choices[0].message.content";
|
|
3937
3955
|
const result = resolvePath(data, extractPath);
|
|
3938
3956
|
if (result === void 0) {
|
|
3939
3957
|
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
@@ -3947,7 +3965,7 @@ ${context != null ? context : "None"}` },
|
|
|
3947
3965
|
*/
|
|
3948
3966
|
chatStream(messages, context) {
|
|
3949
3967
|
return __asyncGenerator(this, null, function* () {
|
|
3950
|
-
var _a2, _b, _c;
|
|
3968
|
+
var _a2, _b, _c, _d, _e, _f, _g2;
|
|
3951
3969
|
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3952
3970
|
const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
|
|
3953
3971
|
const extractPath = ((_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content").replace("message.content", "delta.content");
|
|
@@ -3978,19 +3996,45 @@ ${context != null ? context : "None"}` },
|
|
|
3978
3996
|
stream: true
|
|
3979
3997
|
};
|
|
3980
3998
|
}
|
|
3981
|
-
const
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3999
|
+
const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
|
|
4000
|
+
let streamBody = null;
|
|
4001
|
+
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
4002
|
+
try {
|
|
4003
|
+
const _g3 = globalThis;
|
|
4004
|
+
if (typeof _g3.__retrivoraDispatchChat === "function") {
|
|
4005
|
+
const res = yield new __await(_g3.__retrivoraDispatchChat({
|
|
4006
|
+
model: this.model,
|
|
4007
|
+
messages: formattedMessages,
|
|
4008
|
+
max_tokens: this.maxTokens,
|
|
4009
|
+
temperature: this.temperature,
|
|
4010
|
+
stream: true
|
|
4011
|
+
}, this.apiKey));
|
|
4012
|
+
if (res == null ? void 0 : res.stream) {
|
|
4013
|
+
streamBody = res.stream;
|
|
4014
|
+
} else if ((_f = (_e = (_d = (_c = res == null ? void 0 : res.response) == null ? void 0 : _c.choices) == null ? void 0 : _d[0]) == null ? void 0 : _e.message) == null ? void 0 : _f.content) {
|
|
4015
|
+
yield res.response.choices[0].message.content;
|
|
4016
|
+
return;
|
|
4017
|
+
}
|
|
4018
|
+
}
|
|
4019
|
+
} catch (e) {
|
|
4020
|
+
}
|
|
3989
4021
|
}
|
|
3990
|
-
if (!
|
|
3991
|
-
|
|
4022
|
+
if (!streamBody) {
|
|
4023
|
+
const response = yield new __await(fetch(url, {
|
|
4024
|
+
method: "POST",
|
|
4025
|
+
headers: this.resolvedHeaders,
|
|
4026
|
+
body: JSON.stringify(payload)
|
|
4027
|
+
}));
|
|
4028
|
+
if (!response.ok) {
|
|
4029
|
+
const errorText = yield new __await(response.text().catch(() => response.statusText));
|
|
4030
|
+
throw new Error(`[UniversalLLMAdapter] Streaming request failed (${response.status}): ${errorText}`);
|
|
4031
|
+
}
|
|
4032
|
+
if (!response.body) {
|
|
4033
|
+
throw new Error("[UniversalLLMAdapter] Response body is null \u2014 server did not send a streaming response.");
|
|
4034
|
+
}
|
|
4035
|
+
streamBody = response.body;
|
|
3992
4036
|
}
|
|
3993
|
-
const reader =
|
|
4037
|
+
const reader = streamBody.getReader();
|
|
3994
4038
|
const decoder = new TextDecoder("utf-8");
|
|
3995
4039
|
let buffer = "";
|
|
3996
4040
|
try {
|
|
@@ -3999,7 +4043,7 @@ ${context != null ? context : "None"}` },
|
|
|
3999
4043
|
if (done) break;
|
|
4000
4044
|
buffer += decoder.decode(value, { stream: true });
|
|
4001
4045
|
const lines = buffer.split("\n");
|
|
4002
|
-
buffer = (
|
|
4046
|
+
buffer = (_g2 = lines.pop()) != null ? _g2 : "";
|
|
4003
4047
|
for (const line of lines) {
|
|
4004
4048
|
const trimmed = line.trim();
|
|
4005
4049
|
if (!trimmed || trimmed === "data: [DONE]") continue;
|
|
@@ -4027,7 +4071,7 @@ ${context != null ? context : "None"}` },
|
|
|
4027
4071
|
});
|
|
4028
4072
|
}
|
|
4029
4073
|
async embed(text) {
|
|
4030
|
-
var _a2, _b;
|
|
4074
|
+
var _a2, _b, _c, _d;
|
|
4031
4075
|
const path2 = (_a2 = this.opts.embedPath) != null ? _a2 : "/embeddings";
|
|
4032
4076
|
let payload;
|
|
4033
4077
|
if (this.opts.embedPayloadTemplate) {
|
|
@@ -4041,8 +4085,24 @@ ${context != null ? context : "None"}` },
|
|
|
4041
4085
|
input: text
|
|
4042
4086
|
};
|
|
4043
4087
|
}
|
|
4088
|
+
const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
|
|
4089
|
+
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
4090
|
+
try {
|
|
4091
|
+
const _g2 = globalThis;
|
|
4092
|
+
if (typeof _g2.__retrivoraDispatchEmbedding === "function") {
|
|
4093
|
+
const res = await _g2.__retrivoraDispatchEmbedding({
|
|
4094
|
+
model: this.model,
|
|
4095
|
+
input: text
|
|
4096
|
+
}, this.apiKey);
|
|
4097
|
+
if ((_c = (_b = res == null ? void 0 : res.data) == null ? void 0 : _b[0]) == null ? void 0 : _c.embedding) {
|
|
4098
|
+
return res.data[0].embedding;
|
|
4099
|
+
}
|
|
4100
|
+
}
|
|
4101
|
+
} catch (e) {
|
|
4102
|
+
}
|
|
4103
|
+
}
|
|
4044
4104
|
const { data } = await this.http.post(path2, payload);
|
|
4045
|
-
const extractPath = (
|
|
4105
|
+
const extractPath = (_d = this.opts.embedExtractPath) != null ? _d : "data[0].embedding";
|
|
4046
4106
|
const vector = resolvePath(data, extractPath);
|
|
4047
4107
|
if (!Array.isArray(vector)) {
|
|
4048
4108
|
throw new Error(`[UniversalLLMAdapter] Expected a number array at '${extractPath}' for embeddings.`);
|
|
@@ -8378,8 +8438,11 @@ ${m.content}`).join("\n\n---\n\n");
|
|
|
8378
8438
|
fullSources = fullSources.slice(0, topK);
|
|
8379
8439
|
}
|
|
8380
8440
|
const rerankMs = performance.now() - rerankStart;
|
|
8381
|
-
let context = fullSources.length ? fullSources.map((m, i) =>
|
|
8382
|
-
|
|
8441
|
+
let context = fullSources.length ? fullSources.map((m, i) => {
|
|
8442
|
+
var _a3;
|
|
8443
|
+
return `[Source ${i + 1}]
|
|
8444
|
+
${(_a3 = m == null ? void 0 : m.content) != null ? _a3 : ""}`;
|
|
8445
|
+
}).join("\n\n---\n\n") : "No relevant context found.";
|
|
8383
8446
|
let displayCount = 15;
|
|
8384
8447
|
if (hasMetadataFilter) {
|
|
8385
8448
|
displayCount = fullSources.length;
|
|
@@ -8463,7 +8526,10 @@ ${context}`;
|
|
|
8463
8526
|
if (isSimulatedThinking) {
|
|
8464
8527
|
finalRestrictionSuffix += "\n\n(IMPORTANT: You must think step-by-step before answering. Write your thinking process inside a `<think>...</think>` block. Write the `<think>` block first, then follow it with your final response. Keep the thinking process thorough and detailed. Example: `<think>Thinking details here...</think>Final answer text here.`)";
|
|
8465
8528
|
}
|
|
8466
|
-
const hardenedHistory = [
|
|
8529
|
+
const hardenedHistory = (Array.isArray(history) ? history : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
8530
|
+
role: m.role || "user",
|
|
8531
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
8532
|
+
}));
|
|
8467
8533
|
const userQuestion = { role: "user", content: question + finalRestrictionSuffix };
|
|
8468
8534
|
const messages = [...hardenedHistory, userQuestion];
|
|
8469
8535
|
const systemPrompt = (_v = this.config.llm.systemPrompt) != null ? _v : "";
|
|
@@ -8610,13 +8676,13 @@ ${context}`;
|
|
|
8610
8676
|
rewrittenQuery,
|
|
8611
8677
|
systemPrompt,
|
|
8612
8678
|
userPrompt: question + finalRestrictionSuffix,
|
|
8613
|
-
chunks: sources.map((s) => {
|
|
8614
|
-
var _a3;
|
|
8679
|
+
chunks: (sources || []).filter(Boolean).map((s) => {
|
|
8680
|
+
var _a3, _b2;
|
|
8615
8681
|
return {
|
|
8616
8682
|
id: s.id,
|
|
8617
8683
|
score: s.score,
|
|
8618
|
-
content: s.content,
|
|
8619
|
-
metadata: (
|
|
8684
|
+
content: (_a3 = s == null ? void 0 : s.content) != null ? _a3 : "",
|
|
8685
|
+
metadata: (_b2 = s == null ? void 0 : s.metadata) != null ? _b2 : {},
|
|
8620
8686
|
namespace: ns
|
|
8621
8687
|
};
|
|
8622
8688
|
}),
|
|
@@ -9218,6 +9284,7 @@ ${csv.trim()}`);
|
|
|
9218
9284
|
// src/core/DatabaseStorage.ts
|
|
9219
9285
|
var fs = __toESM(require("fs"));
|
|
9220
9286
|
var path = __toESM(require("path"));
|
|
9287
|
+
var os = __toESM(require("os"));
|
|
9221
9288
|
var DatabaseStorage = class {
|
|
9222
9289
|
constructor(config) {
|
|
9223
9290
|
// Dynamic PG Pool
|
|
@@ -9226,7 +9293,8 @@ var DatabaseStorage = class {
|
|
|
9226
9293
|
this.mongoClient = null;
|
|
9227
9294
|
this.mongoDbName = "";
|
|
9228
9295
|
// Filesystem fallback configuration
|
|
9229
|
-
this.
|
|
9296
|
+
this.isServerless = Boolean(process.env.VERCEL || process.env.AWS_LAMBDA_FUNCTION_NAME || process.env.LAMBDA_TASK_ROOT);
|
|
9297
|
+
this.fallbackDir = this.isServerless ? path.join(os.tmpdir(), ".retrivora") : path.join(process.cwd(), ".retrivora");
|
|
9230
9298
|
this.historyFile = path.join(this.fallbackDir, "history.json");
|
|
9231
9299
|
this.feedbackFile = path.join(this.fallbackDir, "feedback.json");
|
|
9232
9300
|
var _a2, _b, _c, _d, _e;
|
|
@@ -9356,10 +9424,27 @@ var DatabaseStorage = class {
|
|
|
9356
9424
|
}
|
|
9357
9425
|
// Helper for FS fallback writes
|
|
9358
9426
|
writeLocalFile(filePath, data) {
|
|
9359
|
-
|
|
9360
|
-
|
|
9427
|
+
try {
|
|
9428
|
+
const dir = path.dirname(filePath);
|
|
9429
|
+
if (!fs.existsSync(dir)) {
|
|
9430
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
9431
|
+
}
|
|
9432
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
9433
|
+
} catch (err) {
|
|
9434
|
+
if (err.code === "EROFS") {
|
|
9435
|
+
try {
|
|
9436
|
+
const tmpDir = path.join(os.tmpdir(), ".retrivora");
|
|
9437
|
+
if (!fs.existsSync(tmpDir)) {
|
|
9438
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
9439
|
+
}
|
|
9440
|
+
const tmpFilePath = path.join(tmpDir, path.basename(filePath));
|
|
9441
|
+
fs.writeFileSync(tmpFilePath, JSON.stringify(data, null, 2), "utf-8");
|
|
9442
|
+
} catch (e) {
|
|
9443
|
+
}
|
|
9444
|
+
} else {
|
|
9445
|
+
console.warn(`[DatabaseStorage] Failed to write local fallback file: ${err.message}`);
|
|
9446
|
+
}
|
|
9361
9447
|
}
|
|
9362
|
-
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
9363
9448
|
}
|
|
9364
9449
|
// ─── Message History Operations ──────────────────────────────────────────
|
|
9365
9450
|
async saveMessage(sessionId, message) {
|
package/dist/handlers/index.mjs
CHANGED
|
@@ -3872,7 +3872,7 @@ var UniversalLLMAdapter = class {
|
|
|
3872
3872
|
});
|
|
3873
3873
|
}
|
|
3874
3874
|
async chat(messages, context) {
|
|
3875
|
-
var _a2, _b;
|
|
3875
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3876
3876
|
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3877
3877
|
const formattedMessages = [
|
|
3878
3878
|
{ role: "system", content: `${this.systemPrompt}
|
|
@@ -3897,8 +3897,26 @@ ${context != null ? context : "None"}` },
|
|
|
3897
3897
|
temperature: this.temperature
|
|
3898
3898
|
};
|
|
3899
3899
|
}
|
|
3900
|
+
const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
|
|
3901
|
+
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
3902
|
+
try {
|
|
3903
|
+
const _g2 = globalThis;
|
|
3904
|
+
if (typeof _g2.__retrivoraDispatchChat === "function") {
|
|
3905
|
+
const res = await _g2.__retrivoraDispatchChat({
|
|
3906
|
+
model: this.model,
|
|
3907
|
+
messages: formattedMessages,
|
|
3908
|
+
max_tokens: this.maxTokens,
|
|
3909
|
+
temperature: this.temperature
|
|
3910
|
+
}, this.apiKey);
|
|
3911
|
+
if ((_e = (_d = (_c = (_b = res == null ? void 0 : res.response) == null ? void 0 : _b.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) {
|
|
3912
|
+
return res.response.choices[0].message.content;
|
|
3913
|
+
}
|
|
3914
|
+
}
|
|
3915
|
+
} catch (e) {
|
|
3916
|
+
}
|
|
3917
|
+
}
|
|
3900
3918
|
const { data } = await this.http.post(path2, payload);
|
|
3901
|
-
const extractPath = (
|
|
3919
|
+
const extractPath = (_f = this.opts.responseExtractPath) != null ? _f : "choices[0].message.content";
|
|
3902
3920
|
const result = resolvePath(data, extractPath);
|
|
3903
3921
|
if (result === void 0) {
|
|
3904
3922
|
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
@@ -3912,7 +3930,7 @@ ${context != null ? context : "None"}` },
|
|
|
3912
3930
|
*/
|
|
3913
3931
|
chatStream(messages, context) {
|
|
3914
3932
|
return __asyncGenerator(this, null, function* () {
|
|
3915
|
-
var _a2, _b, _c;
|
|
3933
|
+
var _a2, _b, _c, _d, _e, _f, _g2;
|
|
3916
3934
|
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3917
3935
|
const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
|
|
3918
3936
|
const extractPath = ((_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content").replace("message.content", "delta.content");
|
|
@@ -3943,19 +3961,45 @@ ${context != null ? context : "None"}` },
|
|
|
3943
3961
|
stream: true
|
|
3944
3962
|
};
|
|
3945
3963
|
}
|
|
3946
|
-
const
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3964
|
+
const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
|
|
3965
|
+
let streamBody = null;
|
|
3966
|
+
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
3967
|
+
try {
|
|
3968
|
+
const _g3 = globalThis;
|
|
3969
|
+
if (typeof _g3.__retrivoraDispatchChat === "function") {
|
|
3970
|
+
const res = yield new __await(_g3.__retrivoraDispatchChat({
|
|
3971
|
+
model: this.model,
|
|
3972
|
+
messages: formattedMessages,
|
|
3973
|
+
max_tokens: this.maxTokens,
|
|
3974
|
+
temperature: this.temperature,
|
|
3975
|
+
stream: true
|
|
3976
|
+
}, this.apiKey));
|
|
3977
|
+
if (res == null ? void 0 : res.stream) {
|
|
3978
|
+
streamBody = res.stream;
|
|
3979
|
+
} else if ((_f = (_e = (_d = (_c = res == null ? void 0 : res.response) == null ? void 0 : _c.choices) == null ? void 0 : _d[0]) == null ? void 0 : _e.message) == null ? void 0 : _f.content) {
|
|
3980
|
+
yield res.response.choices[0].message.content;
|
|
3981
|
+
return;
|
|
3982
|
+
}
|
|
3983
|
+
}
|
|
3984
|
+
} catch (e) {
|
|
3985
|
+
}
|
|
3954
3986
|
}
|
|
3955
|
-
if (!
|
|
3956
|
-
|
|
3987
|
+
if (!streamBody) {
|
|
3988
|
+
const response = yield new __await(fetch(url, {
|
|
3989
|
+
method: "POST",
|
|
3990
|
+
headers: this.resolvedHeaders,
|
|
3991
|
+
body: JSON.stringify(payload)
|
|
3992
|
+
}));
|
|
3993
|
+
if (!response.ok) {
|
|
3994
|
+
const errorText = yield new __await(response.text().catch(() => response.statusText));
|
|
3995
|
+
throw new Error(`[UniversalLLMAdapter] Streaming request failed (${response.status}): ${errorText}`);
|
|
3996
|
+
}
|
|
3997
|
+
if (!response.body) {
|
|
3998
|
+
throw new Error("[UniversalLLMAdapter] Response body is null \u2014 server did not send a streaming response.");
|
|
3999
|
+
}
|
|
4000
|
+
streamBody = response.body;
|
|
3957
4001
|
}
|
|
3958
|
-
const reader =
|
|
4002
|
+
const reader = streamBody.getReader();
|
|
3959
4003
|
const decoder = new TextDecoder("utf-8");
|
|
3960
4004
|
let buffer = "";
|
|
3961
4005
|
try {
|
|
@@ -3964,7 +4008,7 @@ ${context != null ? context : "None"}` },
|
|
|
3964
4008
|
if (done) break;
|
|
3965
4009
|
buffer += decoder.decode(value, { stream: true });
|
|
3966
4010
|
const lines = buffer.split("\n");
|
|
3967
|
-
buffer = (
|
|
4011
|
+
buffer = (_g2 = lines.pop()) != null ? _g2 : "";
|
|
3968
4012
|
for (const line of lines) {
|
|
3969
4013
|
const trimmed = line.trim();
|
|
3970
4014
|
if (!trimmed || trimmed === "data: [DONE]") continue;
|
|
@@ -3992,7 +4036,7 @@ ${context != null ? context : "None"}` },
|
|
|
3992
4036
|
});
|
|
3993
4037
|
}
|
|
3994
4038
|
async embed(text) {
|
|
3995
|
-
var _a2, _b;
|
|
4039
|
+
var _a2, _b, _c, _d;
|
|
3996
4040
|
const path2 = (_a2 = this.opts.embedPath) != null ? _a2 : "/embeddings";
|
|
3997
4041
|
let payload;
|
|
3998
4042
|
if (this.opts.embedPayloadTemplate) {
|
|
@@ -4006,8 +4050,24 @@ ${context != null ? context : "None"}` },
|
|
|
4006
4050
|
input: text
|
|
4007
4051
|
};
|
|
4008
4052
|
}
|
|
4053
|
+
const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
|
|
4054
|
+
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
4055
|
+
try {
|
|
4056
|
+
const _g2 = globalThis;
|
|
4057
|
+
if (typeof _g2.__retrivoraDispatchEmbedding === "function") {
|
|
4058
|
+
const res = await _g2.__retrivoraDispatchEmbedding({
|
|
4059
|
+
model: this.model,
|
|
4060
|
+
input: text
|
|
4061
|
+
}, this.apiKey);
|
|
4062
|
+
if ((_c = (_b = res == null ? void 0 : res.data) == null ? void 0 : _b[0]) == null ? void 0 : _c.embedding) {
|
|
4063
|
+
return res.data[0].embedding;
|
|
4064
|
+
}
|
|
4065
|
+
}
|
|
4066
|
+
} catch (e) {
|
|
4067
|
+
}
|
|
4068
|
+
}
|
|
4009
4069
|
const { data } = await this.http.post(path2, payload);
|
|
4010
|
-
const extractPath = (
|
|
4070
|
+
const extractPath = (_d = this.opts.embedExtractPath) != null ? _d : "data[0].embedding";
|
|
4011
4071
|
const vector = resolvePath(data, extractPath);
|
|
4012
4072
|
if (!Array.isArray(vector)) {
|
|
4013
4073
|
throw new Error(`[UniversalLLMAdapter] Expected a number array at '${extractPath}' for embeddings.`);
|
|
@@ -8343,8 +8403,11 @@ ${m.content}`).join("\n\n---\n\n");
|
|
|
8343
8403
|
fullSources = fullSources.slice(0, topK);
|
|
8344
8404
|
}
|
|
8345
8405
|
const rerankMs = performance.now() - rerankStart;
|
|
8346
|
-
let context = fullSources.length ? fullSources.map((m, i) =>
|
|
8347
|
-
|
|
8406
|
+
let context = fullSources.length ? fullSources.map((m, i) => {
|
|
8407
|
+
var _a3;
|
|
8408
|
+
return `[Source ${i + 1}]
|
|
8409
|
+
${(_a3 = m == null ? void 0 : m.content) != null ? _a3 : ""}`;
|
|
8410
|
+
}).join("\n\n---\n\n") : "No relevant context found.";
|
|
8348
8411
|
let displayCount = 15;
|
|
8349
8412
|
if (hasMetadataFilter) {
|
|
8350
8413
|
displayCount = fullSources.length;
|
|
@@ -8428,7 +8491,10 @@ ${context}`;
|
|
|
8428
8491
|
if (isSimulatedThinking) {
|
|
8429
8492
|
finalRestrictionSuffix += "\n\n(IMPORTANT: You must think step-by-step before answering. Write your thinking process inside a `<think>...</think>` block. Write the `<think>` block first, then follow it with your final response. Keep the thinking process thorough and detailed. Example: `<think>Thinking details here...</think>Final answer text here.`)";
|
|
8430
8493
|
}
|
|
8431
|
-
const hardenedHistory = [
|
|
8494
|
+
const hardenedHistory = (Array.isArray(history) ? history : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
8495
|
+
role: m.role || "user",
|
|
8496
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
8497
|
+
}));
|
|
8432
8498
|
const userQuestion = { role: "user", content: question + finalRestrictionSuffix };
|
|
8433
8499
|
const messages = [...hardenedHistory, userQuestion];
|
|
8434
8500
|
const systemPrompt = (_v = this.config.llm.systemPrompt) != null ? _v : "";
|
|
@@ -8575,13 +8641,13 @@ ${context}`;
|
|
|
8575
8641
|
rewrittenQuery,
|
|
8576
8642
|
systemPrompt,
|
|
8577
8643
|
userPrompt: question + finalRestrictionSuffix,
|
|
8578
|
-
chunks: sources.map((s) => {
|
|
8579
|
-
var _a3;
|
|
8644
|
+
chunks: (sources || []).filter(Boolean).map((s) => {
|
|
8645
|
+
var _a3, _b2;
|
|
8580
8646
|
return {
|
|
8581
8647
|
id: s.id,
|
|
8582
8648
|
score: s.score,
|
|
8583
|
-
content: s.content,
|
|
8584
|
-
metadata: (
|
|
8649
|
+
content: (_a3 = s == null ? void 0 : s.content) != null ? _a3 : "",
|
|
8650
|
+
metadata: (_b2 = s == null ? void 0 : s.metadata) != null ? _b2 : {},
|
|
8585
8651
|
namespace: ns
|
|
8586
8652
|
};
|
|
8587
8653
|
}),
|
|
@@ -9183,6 +9249,7 @@ ${csv.trim()}`);
|
|
|
9183
9249
|
// src/core/DatabaseStorage.ts
|
|
9184
9250
|
import * as fs from "fs";
|
|
9185
9251
|
import * as path from "path";
|
|
9252
|
+
import * as os from "os";
|
|
9186
9253
|
var DatabaseStorage = class {
|
|
9187
9254
|
constructor(config) {
|
|
9188
9255
|
// Dynamic PG Pool
|
|
@@ -9191,7 +9258,8 @@ var DatabaseStorage = class {
|
|
|
9191
9258
|
this.mongoClient = null;
|
|
9192
9259
|
this.mongoDbName = "";
|
|
9193
9260
|
// Filesystem fallback configuration
|
|
9194
|
-
this.
|
|
9261
|
+
this.isServerless = Boolean(process.env.VERCEL || process.env.AWS_LAMBDA_FUNCTION_NAME || process.env.LAMBDA_TASK_ROOT);
|
|
9262
|
+
this.fallbackDir = this.isServerless ? path.join(os.tmpdir(), ".retrivora") : path.join(process.cwd(), ".retrivora");
|
|
9195
9263
|
this.historyFile = path.join(this.fallbackDir, "history.json");
|
|
9196
9264
|
this.feedbackFile = path.join(this.fallbackDir, "feedback.json");
|
|
9197
9265
|
var _a2, _b, _c, _d, _e;
|
|
@@ -9321,10 +9389,27 @@ var DatabaseStorage = class {
|
|
|
9321
9389
|
}
|
|
9322
9390
|
// Helper for FS fallback writes
|
|
9323
9391
|
writeLocalFile(filePath, data) {
|
|
9324
|
-
|
|
9325
|
-
|
|
9392
|
+
try {
|
|
9393
|
+
const dir = path.dirname(filePath);
|
|
9394
|
+
if (!fs.existsSync(dir)) {
|
|
9395
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
9396
|
+
}
|
|
9397
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
9398
|
+
} catch (err) {
|
|
9399
|
+
if (err.code === "EROFS") {
|
|
9400
|
+
try {
|
|
9401
|
+
const tmpDir = path.join(os.tmpdir(), ".retrivora");
|
|
9402
|
+
if (!fs.existsSync(tmpDir)) {
|
|
9403
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
9404
|
+
}
|
|
9405
|
+
const tmpFilePath = path.join(tmpDir, path.basename(filePath));
|
|
9406
|
+
fs.writeFileSync(tmpFilePath, JSON.stringify(data, null, 2), "utf-8");
|
|
9407
|
+
} catch (e) {
|
|
9408
|
+
}
|
|
9409
|
+
} else {
|
|
9410
|
+
console.warn(`[DatabaseStorage] Failed to write local fallback file: ${err.message}`);
|
|
9411
|
+
}
|
|
9326
9412
|
}
|
|
9327
|
-
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
9328
9413
|
}
|
|
9329
9414
|
// ─── Message History Operations ──────────────────────────────────────────
|
|
9330
9415
|
async saveMessage(sessionId, message) {
|
package/dist/server.js
CHANGED
|
@@ -4007,7 +4007,7 @@ var UniversalLLMAdapter = class {
|
|
|
4007
4007
|
});
|
|
4008
4008
|
}
|
|
4009
4009
|
async chat(messages, context) {
|
|
4010
|
-
var _a2, _b;
|
|
4010
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
4011
4011
|
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
4012
4012
|
const formattedMessages = [
|
|
4013
4013
|
{ role: "system", content: `${this.systemPrompt}
|
|
@@ -4032,8 +4032,26 @@ ${context != null ? context : "None"}` },
|
|
|
4032
4032
|
temperature: this.temperature
|
|
4033
4033
|
};
|
|
4034
4034
|
}
|
|
4035
|
+
const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
|
|
4036
|
+
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
4037
|
+
try {
|
|
4038
|
+
const _g2 = globalThis;
|
|
4039
|
+
if (typeof _g2.__retrivoraDispatchChat === "function") {
|
|
4040
|
+
const res = await _g2.__retrivoraDispatchChat({
|
|
4041
|
+
model: this.model,
|
|
4042
|
+
messages: formattedMessages,
|
|
4043
|
+
max_tokens: this.maxTokens,
|
|
4044
|
+
temperature: this.temperature
|
|
4045
|
+
}, this.apiKey);
|
|
4046
|
+
if ((_e = (_d = (_c = (_b = res == null ? void 0 : res.response) == null ? void 0 : _b.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) {
|
|
4047
|
+
return res.response.choices[0].message.content;
|
|
4048
|
+
}
|
|
4049
|
+
}
|
|
4050
|
+
} catch (e) {
|
|
4051
|
+
}
|
|
4052
|
+
}
|
|
4035
4053
|
const { data } = await this.http.post(path2, payload);
|
|
4036
|
-
const extractPath = (
|
|
4054
|
+
const extractPath = (_f = this.opts.responseExtractPath) != null ? _f : "choices[0].message.content";
|
|
4037
4055
|
const result = resolvePath(data, extractPath);
|
|
4038
4056
|
if (result === void 0) {
|
|
4039
4057
|
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
@@ -4047,7 +4065,7 @@ ${context != null ? context : "None"}` },
|
|
|
4047
4065
|
*/
|
|
4048
4066
|
chatStream(messages, context) {
|
|
4049
4067
|
return __asyncGenerator(this, null, function* () {
|
|
4050
|
-
var _a2, _b, _c;
|
|
4068
|
+
var _a2, _b, _c, _d, _e, _f, _g2;
|
|
4051
4069
|
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
4052
4070
|
const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
|
|
4053
4071
|
const extractPath = ((_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content").replace("message.content", "delta.content");
|
|
@@ -4078,19 +4096,45 @@ ${context != null ? context : "None"}` },
|
|
|
4078
4096
|
stream: true
|
|
4079
4097
|
};
|
|
4080
4098
|
}
|
|
4081
|
-
const
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4099
|
+
const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
|
|
4100
|
+
let streamBody = null;
|
|
4101
|
+
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
4102
|
+
try {
|
|
4103
|
+
const _g3 = globalThis;
|
|
4104
|
+
if (typeof _g3.__retrivoraDispatchChat === "function") {
|
|
4105
|
+
const res = yield new __await(_g3.__retrivoraDispatchChat({
|
|
4106
|
+
model: this.model,
|
|
4107
|
+
messages: formattedMessages,
|
|
4108
|
+
max_tokens: this.maxTokens,
|
|
4109
|
+
temperature: this.temperature,
|
|
4110
|
+
stream: true
|
|
4111
|
+
}, this.apiKey));
|
|
4112
|
+
if (res == null ? void 0 : res.stream) {
|
|
4113
|
+
streamBody = res.stream;
|
|
4114
|
+
} else if ((_f = (_e = (_d = (_c = res == null ? void 0 : res.response) == null ? void 0 : _c.choices) == null ? void 0 : _d[0]) == null ? void 0 : _e.message) == null ? void 0 : _f.content) {
|
|
4115
|
+
yield res.response.choices[0].message.content;
|
|
4116
|
+
return;
|
|
4117
|
+
}
|
|
4118
|
+
}
|
|
4119
|
+
} catch (e) {
|
|
4120
|
+
}
|
|
4089
4121
|
}
|
|
4090
|
-
if (!
|
|
4091
|
-
|
|
4122
|
+
if (!streamBody) {
|
|
4123
|
+
const response = yield new __await(fetch(url, {
|
|
4124
|
+
method: "POST",
|
|
4125
|
+
headers: this.resolvedHeaders,
|
|
4126
|
+
body: JSON.stringify(payload)
|
|
4127
|
+
}));
|
|
4128
|
+
if (!response.ok) {
|
|
4129
|
+
const errorText = yield new __await(response.text().catch(() => response.statusText));
|
|
4130
|
+
throw new Error(`[UniversalLLMAdapter] Streaming request failed (${response.status}): ${errorText}`);
|
|
4131
|
+
}
|
|
4132
|
+
if (!response.body) {
|
|
4133
|
+
throw new Error("[UniversalLLMAdapter] Response body is null \u2014 server did not send a streaming response.");
|
|
4134
|
+
}
|
|
4135
|
+
streamBody = response.body;
|
|
4092
4136
|
}
|
|
4093
|
-
const reader =
|
|
4137
|
+
const reader = streamBody.getReader();
|
|
4094
4138
|
const decoder = new TextDecoder("utf-8");
|
|
4095
4139
|
let buffer = "";
|
|
4096
4140
|
try {
|
|
@@ -4099,7 +4143,7 @@ ${context != null ? context : "None"}` },
|
|
|
4099
4143
|
if (done) break;
|
|
4100
4144
|
buffer += decoder.decode(value, { stream: true });
|
|
4101
4145
|
const lines = buffer.split("\n");
|
|
4102
|
-
buffer = (
|
|
4146
|
+
buffer = (_g2 = lines.pop()) != null ? _g2 : "";
|
|
4103
4147
|
for (const line of lines) {
|
|
4104
4148
|
const trimmed = line.trim();
|
|
4105
4149
|
if (!trimmed || trimmed === "data: [DONE]") continue;
|
|
@@ -4127,7 +4171,7 @@ ${context != null ? context : "None"}` },
|
|
|
4127
4171
|
});
|
|
4128
4172
|
}
|
|
4129
4173
|
async embed(text) {
|
|
4130
|
-
var _a2, _b;
|
|
4174
|
+
var _a2, _b, _c, _d;
|
|
4131
4175
|
const path2 = (_a2 = this.opts.embedPath) != null ? _a2 : "/embeddings";
|
|
4132
4176
|
let payload;
|
|
4133
4177
|
if (this.opts.embedPayloadTemplate) {
|
|
@@ -4141,8 +4185,24 @@ ${context != null ? context : "None"}` },
|
|
|
4141
4185
|
input: text
|
|
4142
4186
|
};
|
|
4143
4187
|
}
|
|
4188
|
+
const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
|
|
4189
|
+
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
4190
|
+
try {
|
|
4191
|
+
const _g2 = globalThis;
|
|
4192
|
+
if (typeof _g2.__retrivoraDispatchEmbedding === "function") {
|
|
4193
|
+
const res = await _g2.__retrivoraDispatchEmbedding({
|
|
4194
|
+
model: this.model,
|
|
4195
|
+
input: text
|
|
4196
|
+
}, this.apiKey);
|
|
4197
|
+
if ((_c = (_b = res == null ? void 0 : res.data) == null ? void 0 : _b[0]) == null ? void 0 : _c.embedding) {
|
|
4198
|
+
return res.data[0].embedding;
|
|
4199
|
+
}
|
|
4200
|
+
}
|
|
4201
|
+
} catch (e) {
|
|
4202
|
+
}
|
|
4203
|
+
}
|
|
4144
4204
|
const { data } = await this.http.post(path2, payload);
|
|
4145
|
-
const extractPath = (
|
|
4205
|
+
const extractPath = (_d = this.opts.embedExtractPath) != null ? _d : "data[0].embedding";
|
|
4146
4206
|
const vector = resolvePath(data, extractPath);
|
|
4147
4207
|
if (!Array.isArray(vector)) {
|
|
4148
4208
|
throw new Error(`[UniversalLLMAdapter] Expected a number array at '${extractPath}' for embeddings.`);
|
|
@@ -8492,8 +8552,11 @@ ${m.content}`).join("\n\n---\n\n");
|
|
|
8492
8552
|
fullSources = fullSources.slice(0, topK);
|
|
8493
8553
|
}
|
|
8494
8554
|
const rerankMs = performance.now() - rerankStart;
|
|
8495
|
-
let context = fullSources.length ? fullSources.map((m, i) =>
|
|
8496
|
-
|
|
8555
|
+
let context = fullSources.length ? fullSources.map((m, i) => {
|
|
8556
|
+
var _a3;
|
|
8557
|
+
return `[Source ${i + 1}]
|
|
8558
|
+
${(_a3 = m == null ? void 0 : m.content) != null ? _a3 : ""}`;
|
|
8559
|
+
}).join("\n\n---\n\n") : "No relevant context found.";
|
|
8497
8560
|
let displayCount = 15;
|
|
8498
8561
|
if (hasMetadataFilter) {
|
|
8499
8562
|
displayCount = fullSources.length;
|
|
@@ -8577,7 +8640,10 @@ ${context}`;
|
|
|
8577
8640
|
if (isSimulatedThinking) {
|
|
8578
8641
|
finalRestrictionSuffix += "\n\n(IMPORTANT: You must think step-by-step before answering. Write your thinking process inside a `<think>...</think>` block. Write the `<think>` block first, then follow it with your final response. Keep the thinking process thorough and detailed. Example: `<think>Thinking details here...</think>Final answer text here.`)";
|
|
8579
8642
|
}
|
|
8580
|
-
const hardenedHistory = [
|
|
8643
|
+
const hardenedHistory = (Array.isArray(history) ? history : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
8644
|
+
role: m.role || "user",
|
|
8645
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
8646
|
+
}));
|
|
8581
8647
|
const userQuestion = { role: "user", content: question + finalRestrictionSuffix };
|
|
8582
8648
|
const messages = [...hardenedHistory, userQuestion];
|
|
8583
8649
|
const systemPrompt = (_v = this.config.llm.systemPrompt) != null ? _v : "";
|
|
@@ -8724,13 +8790,13 @@ ${context}`;
|
|
|
8724
8790
|
rewrittenQuery,
|
|
8725
8791
|
systemPrompt,
|
|
8726
8792
|
userPrompt: question + finalRestrictionSuffix,
|
|
8727
|
-
chunks: sources.map((s) => {
|
|
8728
|
-
var _a3;
|
|
8793
|
+
chunks: (sources || []).filter(Boolean).map((s) => {
|
|
8794
|
+
var _a3, _b2;
|
|
8729
8795
|
return {
|
|
8730
8796
|
id: s.id,
|
|
8731
8797
|
score: s.score,
|
|
8732
|
-
content: s.content,
|
|
8733
|
-
metadata: (
|
|
8798
|
+
content: (_a3 = s == null ? void 0 : s.content) != null ? _a3 : "",
|
|
8799
|
+
metadata: (_b2 = s == null ? void 0 : s.metadata) != null ? _b2 : {},
|
|
8734
8800
|
namespace: ns
|
|
8735
8801
|
};
|
|
8736
8802
|
}),
|
|
@@ -9631,6 +9697,7 @@ var import_server = require("next/server");
|
|
|
9631
9697
|
// src/core/DatabaseStorage.ts
|
|
9632
9698
|
var fs = __toESM(require("fs"));
|
|
9633
9699
|
var path = __toESM(require("path"));
|
|
9700
|
+
var os = __toESM(require("os"));
|
|
9634
9701
|
var DatabaseStorage = class {
|
|
9635
9702
|
constructor(config) {
|
|
9636
9703
|
// Dynamic PG Pool
|
|
@@ -9639,7 +9706,8 @@ var DatabaseStorage = class {
|
|
|
9639
9706
|
this.mongoClient = null;
|
|
9640
9707
|
this.mongoDbName = "";
|
|
9641
9708
|
// Filesystem fallback configuration
|
|
9642
|
-
this.
|
|
9709
|
+
this.isServerless = Boolean(process.env.VERCEL || process.env.AWS_LAMBDA_FUNCTION_NAME || process.env.LAMBDA_TASK_ROOT);
|
|
9710
|
+
this.fallbackDir = this.isServerless ? path.join(os.tmpdir(), ".retrivora") : path.join(process.cwd(), ".retrivora");
|
|
9643
9711
|
this.historyFile = path.join(this.fallbackDir, "history.json");
|
|
9644
9712
|
this.feedbackFile = path.join(this.fallbackDir, "feedback.json");
|
|
9645
9713
|
var _a2, _b, _c, _d, _e;
|
|
@@ -9769,10 +9837,27 @@ var DatabaseStorage = class {
|
|
|
9769
9837
|
}
|
|
9770
9838
|
// Helper for FS fallback writes
|
|
9771
9839
|
writeLocalFile(filePath, data) {
|
|
9772
|
-
|
|
9773
|
-
|
|
9840
|
+
try {
|
|
9841
|
+
const dir = path.dirname(filePath);
|
|
9842
|
+
if (!fs.existsSync(dir)) {
|
|
9843
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
9844
|
+
}
|
|
9845
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
9846
|
+
} catch (err) {
|
|
9847
|
+
if (err.code === "EROFS") {
|
|
9848
|
+
try {
|
|
9849
|
+
const tmpDir = path.join(os.tmpdir(), ".retrivora");
|
|
9850
|
+
if (!fs.existsSync(tmpDir)) {
|
|
9851
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
9852
|
+
}
|
|
9853
|
+
const tmpFilePath = path.join(tmpDir, path.basename(filePath));
|
|
9854
|
+
fs.writeFileSync(tmpFilePath, JSON.stringify(data, null, 2), "utf-8");
|
|
9855
|
+
} catch (e) {
|
|
9856
|
+
}
|
|
9857
|
+
} else {
|
|
9858
|
+
console.warn(`[DatabaseStorage] Failed to write local fallback file: ${err.message}`);
|
|
9859
|
+
}
|
|
9774
9860
|
}
|
|
9775
|
-
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
9776
9861
|
}
|
|
9777
9862
|
// ─── Message History Operations ──────────────────────────────────────────
|
|
9778
9863
|
async saveMessage(sessionId, message) {
|
package/dist/server.mjs
CHANGED
|
@@ -3911,7 +3911,7 @@ var UniversalLLMAdapter = class {
|
|
|
3911
3911
|
});
|
|
3912
3912
|
}
|
|
3913
3913
|
async chat(messages, context) {
|
|
3914
|
-
var _a2, _b;
|
|
3914
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3915
3915
|
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3916
3916
|
const formattedMessages = [
|
|
3917
3917
|
{ role: "system", content: `${this.systemPrompt}
|
|
@@ -3936,8 +3936,26 @@ ${context != null ? context : "None"}` },
|
|
|
3936
3936
|
temperature: this.temperature
|
|
3937
3937
|
};
|
|
3938
3938
|
}
|
|
3939
|
+
const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
|
|
3940
|
+
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
3941
|
+
try {
|
|
3942
|
+
const _g2 = globalThis;
|
|
3943
|
+
if (typeof _g2.__retrivoraDispatchChat === "function") {
|
|
3944
|
+
const res = await _g2.__retrivoraDispatchChat({
|
|
3945
|
+
model: this.model,
|
|
3946
|
+
messages: formattedMessages,
|
|
3947
|
+
max_tokens: this.maxTokens,
|
|
3948
|
+
temperature: this.temperature
|
|
3949
|
+
}, this.apiKey);
|
|
3950
|
+
if ((_e = (_d = (_c = (_b = res == null ? void 0 : res.response) == null ? void 0 : _b.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) {
|
|
3951
|
+
return res.response.choices[0].message.content;
|
|
3952
|
+
}
|
|
3953
|
+
}
|
|
3954
|
+
} catch (e) {
|
|
3955
|
+
}
|
|
3956
|
+
}
|
|
3939
3957
|
const { data } = await this.http.post(path2, payload);
|
|
3940
|
-
const extractPath = (
|
|
3958
|
+
const extractPath = (_f = this.opts.responseExtractPath) != null ? _f : "choices[0].message.content";
|
|
3941
3959
|
const result = resolvePath(data, extractPath);
|
|
3942
3960
|
if (result === void 0) {
|
|
3943
3961
|
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
@@ -3951,7 +3969,7 @@ ${context != null ? context : "None"}` },
|
|
|
3951
3969
|
*/
|
|
3952
3970
|
chatStream(messages, context) {
|
|
3953
3971
|
return __asyncGenerator(this, null, function* () {
|
|
3954
|
-
var _a2, _b, _c;
|
|
3972
|
+
var _a2, _b, _c, _d, _e, _f, _g2;
|
|
3955
3973
|
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3956
3974
|
const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
|
|
3957
3975
|
const extractPath = ((_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content").replace("message.content", "delta.content");
|
|
@@ -3982,19 +4000,45 @@ ${context != null ? context : "None"}` },
|
|
|
3982
4000
|
stream: true
|
|
3983
4001
|
};
|
|
3984
4002
|
}
|
|
3985
|
-
const
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
4003
|
+
const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
|
|
4004
|
+
let streamBody = null;
|
|
4005
|
+
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
4006
|
+
try {
|
|
4007
|
+
const _g3 = globalThis;
|
|
4008
|
+
if (typeof _g3.__retrivoraDispatchChat === "function") {
|
|
4009
|
+
const res = yield new __await(_g3.__retrivoraDispatchChat({
|
|
4010
|
+
model: this.model,
|
|
4011
|
+
messages: formattedMessages,
|
|
4012
|
+
max_tokens: this.maxTokens,
|
|
4013
|
+
temperature: this.temperature,
|
|
4014
|
+
stream: true
|
|
4015
|
+
}, this.apiKey));
|
|
4016
|
+
if (res == null ? void 0 : res.stream) {
|
|
4017
|
+
streamBody = res.stream;
|
|
4018
|
+
} else if ((_f = (_e = (_d = (_c = res == null ? void 0 : res.response) == null ? void 0 : _c.choices) == null ? void 0 : _d[0]) == null ? void 0 : _e.message) == null ? void 0 : _f.content) {
|
|
4019
|
+
yield res.response.choices[0].message.content;
|
|
4020
|
+
return;
|
|
4021
|
+
}
|
|
4022
|
+
}
|
|
4023
|
+
} catch (e) {
|
|
4024
|
+
}
|
|
3993
4025
|
}
|
|
3994
|
-
if (!
|
|
3995
|
-
|
|
4026
|
+
if (!streamBody) {
|
|
4027
|
+
const response = yield new __await(fetch(url, {
|
|
4028
|
+
method: "POST",
|
|
4029
|
+
headers: this.resolvedHeaders,
|
|
4030
|
+
body: JSON.stringify(payload)
|
|
4031
|
+
}));
|
|
4032
|
+
if (!response.ok) {
|
|
4033
|
+
const errorText = yield new __await(response.text().catch(() => response.statusText));
|
|
4034
|
+
throw new Error(`[UniversalLLMAdapter] Streaming request failed (${response.status}): ${errorText}`);
|
|
4035
|
+
}
|
|
4036
|
+
if (!response.body) {
|
|
4037
|
+
throw new Error("[UniversalLLMAdapter] Response body is null \u2014 server did not send a streaming response.");
|
|
4038
|
+
}
|
|
4039
|
+
streamBody = response.body;
|
|
3996
4040
|
}
|
|
3997
|
-
const reader =
|
|
4041
|
+
const reader = streamBody.getReader();
|
|
3998
4042
|
const decoder = new TextDecoder("utf-8");
|
|
3999
4043
|
let buffer = "";
|
|
4000
4044
|
try {
|
|
@@ -4003,7 +4047,7 @@ ${context != null ? context : "None"}` },
|
|
|
4003
4047
|
if (done) break;
|
|
4004
4048
|
buffer += decoder.decode(value, { stream: true });
|
|
4005
4049
|
const lines = buffer.split("\n");
|
|
4006
|
-
buffer = (
|
|
4050
|
+
buffer = (_g2 = lines.pop()) != null ? _g2 : "";
|
|
4007
4051
|
for (const line of lines) {
|
|
4008
4052
|
const trimmed = line.trim();
|
|
4009
4053
|
if (!trimmed || trimmed === "data: [DONE]") continue;
|
|
@@ -4031,7 +4075,7 @@ ${context != null ? context : "None"}` },
|
|
|
4031
4075
|
});
|
|
4032
4076
|
}
|
|
4033
4077
|
async embed(text) {
|
|
4034
|
-
var _a2, _b;
|
|
4078
|
+
var _a2, _b, _c, _d;
|
|
4035
4079
|
const path2 = (_a2 = this.opts.embedPath) != null ? _a2 : "/embeddings";
|
|
4036
4080
|
let payload;
|
|
4037
4081
|
if (this.opts.embedPayloadTemplate) {
|
|
@@ -4045,8 +4089,24 @@ ${context != null ? context : "None"}` },
|
|
|
4045
4089
|
input: text
|
|
4046
4090
|
};
|
|
4047
4091
|
}
|
|
4092
|
+
const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
|
|
4093
|
+
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
4094
|
+
try {
|
|
4095
|
+
const _g2 = globalThis;
|
|
4096
|
+
if (typeof _g2.__retrivoraDispatchEmbedding === "function") {
|
|
4097
|
+
const res = await _g2.__retrivoraDispatchEmbedding({
|
|
4098
|
+
model: this.model,
|
|
4099
|
+
input: text
|
|
4100
|
+
}, this.apiKey);
|
|
4101
|
+
if ((_c = (_b = res == null ? void 0 : res.data) == null ? void 0 : _b[0]) == null ? void 0 : _c.embedding) {
|
|
4102
|
+
return res.data[0].embedding;
|
|
4103
|
+
}
|
|
4104
|
+
}
|
|
4105
|
+
} catch (e) {
|
|
4106
|
+
}
|
|
4107
|
+
}
|
|
4048
4108
|
const { data } = await this.http.post(path2, payload);
|
|
4049
|
-
const extractPath = (
|
|
4109
|
+
const extractPath = (_d = this.opts.embedExtractPath) != null ? _d : "data[0].embedding";
|
|
4050
4110
|
const vector = resolvePath(data, extractPath);
|
|
4051
4111
|
if (!Array.isArray(vector)) {
|
|
4052
4112
|
throw new Error(`[UniversalLLMAdapter] Expected a number array at '${extractPath}' for embeddings.`);
|
|
@@ -8396,8 +8456,11 @@ ${m.content}`).join("\n\n---\n\n");
|
|
|
8396
8456
|
fullSources = fullSources.slice(0, topK);
|
|
8397
8457
|
}
|
|
8398
8458
|
const rerankMs = performance.now() - rerankStart;
|
|
8399
|
-
let context = fullSources.length ? fullSources.map((m, i) =>
|
|
8400
|
-
|
|
8459
|
+
let context = fullSources.length ? fullSources.map((m, i) => {
|
|
8460
|
+
var _a3;
|
|
8461
|
+
return `[Source ${i + 1}]
|
|
8462
|
+
${(_a3 = m == null ? void 0 : m.content) != null ? _a3 : ""}`;
|
|
8463
|
+
}).join("\n\n---\n\n") : "No relevant context found.";
|
|
8401
8464
|
let displayCount = 15;
|
|
8402
8465
|
if (hasMetadataFilter) {
|
|
8403
8466
|
displayCount = fullSources.length;
|
|
@@ -8481,7 +8544,10 @@ ${context}`;
|
|
|
8481
8544
|
if (isSimulatedThinking) {
|
|
8482
8545
|
finalRestrictionSuffix += "\n\n(IMPORTANT: You must think step-by-step before answering. Write your thinking process inside a `<think>...</think>` block. Write the `<think>` block first, then follow it with your final response. Keep the thinking process thorough and detailed. Example: `<think>Thinking details here...</think>Final answer text here.`)";
|
|
8483
8546
|
}
|
|
8484
|
-
const hardenedHistory = [
|
|
8547
|
+
const hardenedHistory = (Array.isArray(history) ? history : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
8548
|
+
role: m.role || "user",
|
|
8549
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
8550
|
+
}));
|
|
8485
8551
|
const userQuestion = { role: "user", content: question + finalRestrictionSuffix };
|
|
8486
8552
|
const messages = [...hardenedHistory, userQuestion];
|
|
8487
8553
|
const systemPrompt = (_v = this.config.llm.systemPrompt) != null ? _v : "";
|
|
@@ -8628,13 +8694,13 @@ ${context}`;
|
|
|
8628
8694
|
rewrittenQuery,
|
|
8629
8695
|
systemPrompt,
|
|
8630
8696
|
userPrompt: question + finalRestrictionSuffix,
|
|
8631
|
-
chunks: sources.map((s) => {
|
|
8632
|
-
var _a3;
|
|
8697
|
+
chunks: (sources || []).filter(Boolean).map((s) => {
|
|
8698
|
+
var _a3, _b2;
|
|
8633
8699
|
return {
|
|
8634
8700
|
id: s.id,
|
|
8635
8701
|
score: s.score,
|
|
8636
|
-
content: s.content,
|
|
8637
|
-
metadata: (
|
|
8702
|
+
content: (_a3 = s == null ? void 0 : s.content) != null ? _a3 : "",
|
|
8703
|
+
metadata: (_b2 = s == null ? void 0 : s.metadata) != null ? _b2 : {},
|
|
8638
8704
|
namespace: ns
|
|
8639
8705
|
};
|
|
8640
8706
|
}),
|
|
@@ -9535,6 +9601,7 @@ import { NextResponse } from "next/server";
|
|
|
9535
9601
|
// src/core/DatabaseStorage.ts
|
|
9536
9602
|
import * as fs from "fs";
|
|
9537
9603
|
import * as path from "path";
|
|
9604
|
+
import * as os from "os";
|
|
9538
9605
|
var DatabaseStorage = class {
|
|
9539
9606
|
constructor(config) {
|
|
9540
9607
|
// Dynamic PG Pool
|
|
@@ -9543,7 +9610,8 @@ var DatabaseStorage = class {
|
|
|
9543
9610
|
this.mongoClient = null;
|
|
9544
9611
|
this.mongoDbName = "";
|
|
9545
9612
|
// Filesystem fallback configuration
|
|
9546
|
-
this.
|
|
9613
|
+
this.isServerless = Boolean(process.env.VERCEL || process.env.AWS_LAMBDA_FUNCTION_NAME || process.env.LAMBDA_TASK_ROOT);
|
|
9614
|
+
this.fallbackDir = this.isServerless ? path.join(os.tmpdir(), ".retrivora") : path.join(process.cwd(), ".retrivora");
|
|
9547
9615
|
this.historyFile = path.join(this.fallbackDir, "history.json");
|
|
9548
9616
|
this.feedbackFile = path.join(this.fallbackDir, "feedback.json");
|
|
9549
9617
|
var _a2, _b, _c, _d, _e;
|
|
@@ -9673,10 +9741,27 @@ var DatabaseStorage = class {
|
|
|
9673
9741
|
}
|
|
9674
9742
|
// Helper for FS fallback writes
|
|
9675
9743
|
writeLocalFile(filePath, data) {
|
|
9676
|
-
|
|
9677
|
-
|
|
9744
|
+
try {
|
|
9745
|
+
const dir = path.dirname(filePath);
|
|
9746
|
+
if (!fs.existsSync(dir)) {
|
|
9747
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
9748
|
+
}
|
|
9749
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
9750
|
+
} catch (err) {
|
|
9751
|
+
if (err.code === "EROFS") {
|
|
9752
|
+
try {
|
|
9753
|
+
const tmpDir = path.join(os.tmpdir(), ".retrivora");
|
|
9754
|
+
if (!fs.existsSync(tmpDir)) {
|
|
9755
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
9756
|
+
}
|
|
9757
|
+
const tmpFilePath = path.join(tmpDir, path.basename(filePath));
|
|
9758
|
+
fs.writeFileSync(tmpFilePath, JSON.stringify(data, null, 2), "utf-8");
|
|
9759
|
+
} catch (e) {
|
|
9760
|
+
}
|
|
9761
|
+
} else {
|
|
9762
|
+
console.warn(`[DatabaseStorage] Failed to write local fallback file: ${err.message}`);
|
|
9763
|
+
}
|
|
9678
9764
|
}
|
|
9679
|
-
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
9680
9765
|
}
|
|
9681
9766
|
// ─── Message History Operations ──────────────────────────────────────────
|
|
9682
9767
|
async saveMessage(sessionId, message) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retrivora-ai/rag-engine",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6",
|
|
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": "UNLICENSED",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
+
import * as os from 'os';
|
|
3
4
|
import { RagConfig } from '../config/RagConfig';
|
|
4
5
|
import { LicenseVerifier } from './LicenseVerifier';
|
|
5
6
|
|
|
@@ -35,7 +36,10 @@ export class DatabaseStorage {
|
|
|
35
36
|
private feedbackTableName: string;
|
|
36
37
|
|
|
37
38
|
// Filesystem fallback configuration
|
|
38
|
-
private
|
|
39
|
+
private isServerless = Boolean(process.env.VERCEL || process.env.AWS_LAMBDA_FUNCTION_NAME || process.env.LAMBDA_TASK_ROOT);
|
|
40
|
+
private fallbackDir = this.isServerless
|
|
41
|
+
? path.join(os.tmpdir(), '.retrivora')
|
|
42
|
+
: path.join(process.cwd(), '.retrivora');
|
|
39
43
|
private historyFile = path.join(this.fallbackDir, 'history.json');
|
|
40
44
|
private feedbackFile = path.join(this.fallbackDir, 'feedback.json');
|
|
41
45
|
|
|
@@ -191,10 +195,28 @@ export class DatabaseStorage {
|
|
|
191
195
|
|
|
192
196
|
// Helper for FS fallback writes
|
|
193
197
|
private writeLocalFile(filePath: string, data: any[]): void {
|
|
194
|
-
|
|
195
|
-
|
|
198
|
+
try {
|
|
199
|
+
const dir = path.dirname(filePath);
|
|
200
|
+
if (!fs.existsSync(dir)) {
|
|
201
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
202
|
+
}
|
|
203
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');
|
|
204
|
+
} catch (err: any) {
|
|
205
|
+
if (err.code === 'EROFS') {
|
|
206
|
+
try {
|
|
207
|
+
const tmpDir = path.join(os.tmpdir(), '.retrivora');
|
|
208
|
+
if (!fs.existsSync(tmpDir)) {
|
|
209
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
210
|
+
}
|
|
211
|
+
const tmpFilePath = path.join(tmpDir, path.basename(filePath));
|
|
212
|
+
fs.writeFileSync(tmpFilePath, JSON.stringify(data, null, 2), 'utf-8');
|
|
213
|
+
} catch {
|
|
214
|
+
/* ignore write failure in read-only environment */
|
|
215
|
+
}
|
|
216
|
+
} else {
|
|
217
|
+
console.warn(`[DatabaseStorage] Failed to write local fallback file: ${err.message}`);
|
|
218
|
+
}
|
|
196
219
|
}
|
|
197
|
-
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');
|
|
198
220
|
}
|
|
199
221
|
|
|
200
222
|
// ─── Message History Operations ──────────────────────────────────────────
|
package/src/core/Pipeline.ts
CHANGED
|
@@ -608,7 +608,7 @@ You are a helpful assistant. Use the provided context to answer questions accura
|
|
|
608
608
|
|
|
609
609
|
// 4. Context Augmentation - Review all retrieved/reranked sources for full comprehension
|
|
610
610
|
let context = fullSources.length
|
|
611
|
-
? fullSources.map((m, i) => `[Source ${i + 1}]\n${m
|
|
611
|
+
? fullSources.map((m, i) => `[Source ${i + 1}]\n${m?.content ?? ''}`).join('\n\n---\n\n')
|
|
612
612
|
: 'No relevant context found.';
|
|
613
613
|
|
|
614
614
|
// Count the records of relevant sources to pass into the slice dynamically
|
|
@@ -722,7 +722,12 @@ You are a helpful assistant. Use the provided context to answer questions accura
|
|
|
722
722
|
finalRestrictionSuffix += '\n\n(IMPORTANT: You must think step-by-step before answering. Write your thinking process inside a `<think>...</think>` block. Write the `<think>` block first, then follow it with your final response. Keep the thinking process thorough and detailed. Example: `<think>Thinking details here...</think>Final answer text here.`)';
|
|
723
723
|
}
|
|
724
724
|
|
|
725
|
-
const hardenedHistory = [
|
|
725
|
+
const hardenedHistory = (Array.isArray(history) ? history : [])
|
|
726
|
+
.filter((m): m is ChatMessage => Boolean(m && typeof m === 'object'))
|
|
727
|
+
.map((m) => ({
|
|
728
|
+
role: m.role || 'user',
|
|
729
|
+
content: typeof m.content === 'string' ? m.content : (m.content != null ? String(m.content) : ''),
|
|
730
|
+
}));
|
|
726
731
|
const userQuestion = { role: 'user', content: question + finalRestrictionSuffix } as ChatMessage;
|
|
727
732
|
const messages: ChatMessage[] = [...hardenedHistory, userQuestion];
|
|
728
733
|
|
|
@@ -880,11 +885,11 @@ You are a helpful assistant. Use the provided context to answer questions accura
|
|
|
880
885
|
rewrittenQuery,
|
|
881
886
|
systemPrompt,
|
|
882
887
|
userPrompt: question + finalRestrictionSuffix,
|
|
883
|
-
chunks: sources.map((s) => ({
|
|
888
|
+
chunks: (sources || []).filter(Boolean).map((s) => ({
|
|
884
889
|
id: s.id,
|
|
885
890
|
score: s.score,
|
|
886
|
-
content: s
|
|
887
|
-
metadata: s
|
|
891
|
+
content: s?.content ?? '',
|
|
892
|
+
metadata: s?.metadata ?? {},
|
|
888
893
|
namespace: ns,
|
|
889
894
|
} satisfies RetrievedChunk)),
|
|
890
895
|
latency,
|
|
@@ -94,6 +94,27 @@ export class UniversalLLMAdapter implements ILLMProvider {
|
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
const isSelfHost = this.baseUrl.includes('retrivora.com') || this.baseUrl.includes('localhost');
|
|
98
|
+
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
99
|
+
try {
|
|
100
|
+
const _g = globalThis as any;
|
|
101
|
+
if (typeof _g.__retrivoraDispatchChat === 'function') {
|
|
102
|
+
const res = await _g.__retrivoraDispatchChat({
|
|
103
|
+
model: this.model,
|
|
104
|
+
messages: formattedMessages as any,
|
|
105
|
+
max_tokens: this.maxTokens,
|
|
106
|
+
temperature: this.temperature,
|
|
107
|
+
}, this.apiKey);
|
|
108
|
+
|
|
109
|
+
if (res?.response?.choices?.[0]?.message?.content) {
|
|
110
|
+
return res.response.choices[0].message.content;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
} catch {
|
|
114
|
+
/* proceed to HTTP fetch */
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
97
118
|
const { data } = await this.http.post(path, payload);
|
|
98
119
|
|
|
99
120
|
const extractPath = this.opts.responseExtractPath ?? 'choices[0].message.content';
|
|
@@ -145,22 +166,52 @@ export class UniversalLLMAdapter implements ILLMProvider {
|
|
|
145
166
|
};
|
|
146
167
|
}
|
|
147
168
|
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
169
|
+
const isSelfHost = this.baseUrl.includes('retrivora.com') || this.baseUrl.includes('localhost');
|
|
170
|
+
let streamBody: ReadableStream<Uint8Array> | null = null;
|
|
171
|
+
|
|
172
|
+
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
173
|
+
try {
|
|
174
|
+
const _g = globalThis as any;
|
|
175
|
+
if (typeof _g.__retrivoraDispatchChat === 'function') {
|
|
176
|
+
const res = await _g.__retrivoraDispatchChat({
|
|
177
|
+
model: this.model,
|
|
178
|
+
messages: formattedMessages as any,
|
|
179
|
+
max_tokens: this.maxTokens,
|
|
180
|
+
temperature: this.temperature,
|
|
181
|
+
stream: true,
|
|
182
|
+
}, this.apiKey);
|
|
183
|
+
|
|
184
|
+
if (res?.stream) {
|
|
185
|
+
streamBody = res.stream as ReadableStream<Uint8Array>;
|
|
186
|
+
} else if (res?.response?.choices?.[0]?.message?.content) {
|
|
187
|
+
yield res.response.choices[0].message.content;
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
} catch {
|
|
192
|
+
/* proceed to HTTP fetch */
|
|
193
|
+
}
|
|
157
194
|
}
|
|
158
195
|
|
|
159
|
-
if (!
|
|
160
|
-
|
|
196
|
+
if (!streamBody) {
|
|
197
|
+
const response = await fetch(url, {
|
|
198
|
+
method: 'POST',
|
|
199
|
+
headers: this.resolvedHeaders,
|
|
200
|
+
body: JSON.stringify(payload),
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
if (!response.ok) {
|
|
204
|
+
const errorText = await response.text().catch(() => response.statusText);
|
|
205
|
+
throw new Error(`[UniversalLLMAdapter] Streaming request failed (${response.status}): ${errorText}`);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (!response.body) {
|
|
209
|
+
throw new Error('[UniversalLLMAdapter] Response body is null — server did not send a streaming response.');
|
|
210
|
+
}
|
|
211
|
+
streamBody = response.body;
|
|
161
212
|
}
|
|
162
213
|
|
|
163
|
-
const reader =
|
|
214
|
+
const reader = streamBody.getReader();
|
|
164
215
|
const decoder = new TextDecoder('utf-8');
|
|
165
216
|
let buffer = '';
|
|
166
217
|
|
|
@@ -218,6 +269,25 @@ export class UniversalLLMAdapter implements ILLMProvider {
|
|
|
218
269
|
};
|
|
219
270
|
}
|
|
220
271
|
|
|
272
|
+
const isSelfHost = this.baseUrl.includes('retrivora.com') || this.baseUrl.includes('localhost');
|
|
273
|
+
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
274
|
+
try {
|
|
275
|
+
const _g = globalThis as any;
|
|
276
|
+
if (typeof _g.__retrivoraDispatchEmbedding === 'function') {
|
|
277
|
+
const res = await _g.__retrivoraDispatchEmbedding({
|
|
278
|
+
model: this.model,
|
|
279
|
+
input: text,
|
|
280
|
+
}, this.apiKey);
|
|
281
|
+
|
|
282
|
+
if (res?.data?.[0]?.embedding) {
|
|
283
|
+
return res.data[0].embedding;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
} catch {
|
|
287
|
+
/* proceed to HTTP fetch */
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
221
291
|
const { data } = await this.http.post(path, payload);
|
|
222
292
|
|
|
223
293
|
const extractPath = this.opts.embedExtractPath ?? 'data[0].embedding';
|