@retrivora-ai/rag-engine 2.0.4 → 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 +486 -356
- package/dist/handlers/index.mjs +488 -358
- package/dist/server.js +486 -356
- package/dist/server.mjs +488 -358
- package/package.json +2 -2
- package/src/config/serverConfig.ts +40 -13
- package/src/core/DatabaseStorage.ts +26 -4
- package/src/core/Pipeline.ts +10 -5
- package/src/handlers/index.ts +22 -9
- package/src/index.css +3956 -0
- package/src/llm/providers/OllamaProvider.ts +4 -2
- package/src/llm/providers/UniversalLLMAdapter.ts +82 -12
package/dist/server.mjs
CHANGED
|
@@ -1239,7 +1239,7 @@ __export(QdrantProvider_exports, {
|
|
|
1239
1239
|
QdrantProvider: () => QdrantProvider
|
|
1240
1240
|
});
|
|
1241
1241
|
import axios4 from "axios";
|
|
1242
|
-
import
|
|
1242
|
+
import crypto2 from "crypto";
|
|
1243
1243
|
var QdrantProvider;
|
|
1244
1244
|
var init_QdrantProvider = __esm({
|
|
1245
1245
|
"src/providers/vectordb/QdrantProvider.ts"() {
|
|
@@ -1471,7 +1471,7 @@ var init_QdrantProvider = __esm({
|
|
|
1471
1471
|
if (typeof id === "number") return id;
|
|
1472
1472
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1473
1473
|
if (uuidRegex.test(id)) return id.toLowerCase();
|
|
1474
|
-
const hash =
|
|
1474
|
+
const hash = crypto2.createHash("md5").update(id).digest("hex");
|
|
1475
1475
|
return `${hash.slice(0, 8)}-${hash.slice(8, 12)}-${hash.slice(12, 16)}-${hash.slice(16, 20)}-${hash.slice(20, 32)}`;
|
|
1476
1476
|
}
|
|
1477
1477
|
async disconnect() {
|
|
@@ -2055,6 +2055,285 @@ var init_SimpleGraphProvider = __esm({
|
|
|
2055
2055
|
// src/core/ConfigResolver.ts
|
|
2056
2056
|
init_templateUtils();
|
|
2057
2057
|
|
|
2058
|
+
// src/core/LicenseVerifier.ts
|
|
2059
|
+
import * as crypto from "crypto";
|
|
2060
|
+
|
|
2061
|
+
// src/exceptions/index.ts
|
|
2062
|
+
var RetrivoraError = class extends Error {
|
|
2063
|
+
constructor(message, code, details) {
|
|
2064
|
+
super(message);
|
|
2065
|
+
this.name = new.target.name;
|
|
2066
|
+
this.code = code;
|
|
2067
|
+
this.details = details;
|
|
2068
|
+
}
|
|
2069
|
+
};
|
|
2070
|
+
var ProviderNotFoundException = class extends RetrivoraError {
|
|
2071
|
+
constructor(providerType, provider, details) {
|
|
2072
|
+
super(`Unsupported ${providerType} provider: ${provider}`, "PROVIDER_NOT_FOUND", details);
|
|
2073
|
+
}
|
|
2074
|
+
};
|
|
2075
|
+
var EmbeddingFailedException = class extends RetrivoraError {
|
|
2076
|
+
constructor(message = "Embedding generation failed", details) {
|
|
2077
|
+
super(message, "EMBEDDING_FAILED", details);
|
|
2078
|
+
}
|
|
2079
|
+
};
|
|
2080
|
+
var RetrievalException = class extends RetrivoraError {
|
|
2081
|
+
constructor(message = "Retrieval failed", details) {
|
|
2082
|
+
super(message, "RETRIEVAL_FAILED", details);
|
|
2083
|
+
}
|
|
2084
|
+
};
|
|
2085
|
+
var RateLimitException = class extends RetrivoraError {
|
|
2086
|
+
constructor(message = "Provider rate limit exceeded", details) {
|
|
2087
|
+
super(message, "RATE_LIMITED", details);
|
|
2088
|
+
}
|
|
2089
|
+
};
|
|
2090
|
+
var ConfigurationException = class extends RetrivoraError {
|
|
2091
|
+
constructor(message, details) {
|
|
2092
|
+
super(message, "CONFIGURATION_ERROR", details);
|
|
2093
|
+
}
|
|
2094
|
+
};
|
|
2095
|
+
var AuthenticationException = class extends RetrivoraError {
|
|
2096
|
+
constructor(message = "Provider authentication failed", details) {
|
|
2097
|
+
super(message, "AUTHENTICATION_ERROR", details);
|
|
2098
|
+
}
|
|
2099
|
+
};
|
|
2100
|
+
function wrapError(err, defaultCode, defaultMessage) {
|
|
2101
|
+
var _a2;
|
|
2102
|
+
if (err instanceof RetrivoraError) {
|
|
2103
|
+
return err;
|
|
2104
|
+
}
|
|
2105
|
+
const error = err;
|
|
2106
|
+
const message = (error == null ? void 0 : error.message) || defaultMessage || String(err);
|
|
2107
|
+
const status = (error == null ? void 0 : error.status) || (error == null ? void 0 : error.statusCode) || ((_a2 = error == null ? void 0 : error.response) == null ? void 0 : _a2.status);
|
|
2108
|
+
const code = error == null ? void 0 : error.code;
|
|
2109
|
+
if (status === 429 || /rate[- ]?limit/i.test(message) || code === "RATE_LIMIT_EXCEEDED") {
|
|
2110
|
+
return new RateLimitException(message, err);
|
|
2111
|
+
}
|
|
2112
|
+
if (status === 401 || status === 403 || /unauthorized|auth|api[- ]?key/i.test(message) || code === "INVALID_API_KEY") {
|
|
2113
|
+
return new AuthenticationException(message, err);
|
|
2114
|
+
}
|
|
2115
|
+
switch (defaultCode) {
|
|
2116
|
+
case "PROVIDER_NOT_FOUND":
|
|
2117
|
+
return new ProviderNotFoundException("provider", message, err);
|
|
2118
|
+
case "EMBEDDING_FAILED":
|
|
2119
|
+
return new EmbeddingFailedException(message, err);
|
|
2120
|
+
case "RETRIEVAL_FAILED":
|
|
2121
|
+
return new RetrievalException(message, err);
|
|
2122
|
+
case "RATE_LIMITED":
|
|
2123
|
+
return new RateLimitException(message, err);
|
|
2124
|
+
case "CONFIGURATION_ERROR":
|
|
2125
|
+
return new ConfigurationException(message, err);
|
|
2126
|
+
case "AUTHENTICATION_ERROR":
|
|
2127
|
+
return new AuthenticationException(message, err);
|
|
2128
|
+
default:
|
|
2129
|
+
return new RetrivoraError(message, defaultCode, err);
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2133
|
+
// src/core/LicenseVerifier.ts
|
|
2134
|
+
var LicenseVerifier = class {
|
|
2135
|
+
/**
|
|
2136
|
+
* Decodes, verifies signature, and checks metadata of a license key.
|
|
2137
|
+
*
|
|
2138
|
+
* @param licenseKey - Base64url signed JWT license key.
|
|
2139
|
+
* @param currentProjectId - Project namespace ID.
|
|
2140
|
+
* @param publicKeyOverride - Optional override for unit/integration tests.
|
|
2141
|
+
*/
|
|
2142
|
+
static verify(licenseKey, currentProjectId, provider, publicKeyOverride) {
|
|
2143
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
2144
|
+
const now = Date.now();
|
|
2145
|
+
if (licenseKey) {
|
|
2146
|
+
const cacheKey = `${licenseKey}:${currentProjectId}:${provider || ""}:${publicKeyOverride || ""}`;
|
|
2147
|
+
const cached = this.cache.get(cacheKey);
|
|
2148
|
+
if (cached && now - cached.cachedAt < this.CACHE_TTL_MS) {
|
|
2149
|
+
const currentTimestampSec = Math.floor(now / 1e3);
|
|
2150
|
+
if (cached.payload.expiresAt && currentTimestampSec > cached.payload.expiresAt) {
|
|
2151
|
+
this.cache.delete(cacheKey);
|
|
2152
|
+
} else {
|
|
2153
|
+
return cached.payload;
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
if (!licenseKey) {
|
|
2158
|
+
if (isProduction) {
|
|
2159
|
+
throw new ConfigurationException(
|
|
2160
|
+
"[Retrivora SDK] License key (licenseKey) is required in production environments."
|
|
2161
|
+
);
|
|
2162
|
+
}
|
|
2163
|
+
console.warn(
|
|
2164
|
+
`\x1B[33m[Retrivora SDK] WARNING: Running without a license key. This namespace (${currentProjectId}) is permitted for local development only.\x1B[0m`
|
|
2165
|
+
);
|
|
2166
|
+
return {
|
|
2167
|
+
projectId: currentProjectId,
|
|
2168
|
+
expiresAt: Math.floor(Date.now() / 1e3) + 86400,
|
|
2169
|
+
// Valid for 24h
|
|
2170
|
+
tier: "hobby"
|
|
2171
|
+
};
|
|
2172
|
+
}
|
|
2173
|
+
try {
|
|
2174
|
+
const parts = licenseKey.split(".");
|
|
2175
|
+
if (parts.length !== 3) {
|
|
2176
|
+
throw new Error("Malformed token structure (expected 3 parts).");
|
|
2177
|
+
}
|
|
2178
|
+
const [headerB64, payloadB64, signatureB64] = parts;
|
|
2179
|
+
const dataToVerify = `${headerB64}.${payloadB64}`;
|
|
2180
|
+
const publicKey = publicKeyOverride != null ? publicKeyOverride : this.PUBLIC_KEY;
|
|
2181
|
+
const signature = Buffer.from(signatureB64, "base64url");
|
|
2182
|
+
const data = Buffer.from(dataToVerify);
|
|
2183
|
+
const isValid = crypto.verify(
|
|
2184
|
+
"sha256",
|
|
2185
|
+
data,
|
|
2186
|
+
publicKey,
|
|
2187
|
+
signature
|
|
2188
|
+
);
|
|
2189
|
+
if (!isValid) {
|
|
2190
|
+
throw new Error("Signature verification failed.");
|
|
2191
|
+
}
|
|
2192
|
+
const payload = JSON.parse(
|
|
2193
|
+
Buffer.from(payloadB64, "base64url").toString("utf8")
|
|
2194
|
+
);
|
|
2195
|
+
if (!payload.projectId) {
|
|
2196
|
+
throw new Error('License payload is missing "projectId".');
|
|
2197
|
+
}
|
|
2198
|
+
if (payload.projectId !== currentProjectId) {
|
|
2199
|
+
throw new Error(
|
|
2200
|
+
`Project ID mismatch. License is bound to project namespace "${payload.projectId}" but configuration has "${currentProjectId}".`
|
|
2201
|
+
);
|
|
2202
|
+
}
|
|
2203
|
+
if (!payload.expiresAt) {
|
|
2204
|
+
throw new Error('License payload is missing expiration ("expiresAt").');
|
|
2205
|
+
}
|
|
2206
|
+
const currentTimestampSec = Math.floor(Date.now() / 1e3);
|
|
2207
|
+
if (currentTimestampSec > payload.expiresAt) {
|
|
2208
|
+
throw new Error(
|
|
2209
|
+
`License key has expired. Expiration: ${new Date(
|
|
2210
|
+
payload.expiresAt * 1e3
|
|
2211
|
+
).toDateString()}`
|
|
2212
|
+
);
|
|
2213
|
+
}
|
|
2214
|
+
if (isProduction && provider) {
|
|
2215
|
+
const tier = (payload.tier || "").toLowerCase();
|
|
2216
|
+
const normalizedProvider = provider.toLowerCase();
|
|
2217
|
+
if (tier === "hobby") {
|
|
2218
|
+
const allowedHobby = ["postgresql", "pgvector", "supabase"];
|
|
2219
|
+
if (!allowedHobby.includes(normalizedProvider)) {
|
|
2220
|
+
throw new Error(
|
|
2221
|
+
`The database provider "${provider}" is not allowed on the Hobby tier. Hobby tier is restricted to PostgreSQL and Supabase. Please upgrade to a Developer Pro or Enterprise plan.`
|
|
2222
|
+
);
|
|
2223
|
+
}
|
|
2224
|
+
} else if (tier === "pro" || tier === "developer_pro" || tier === "premium" || tier === "growth" || tier === "free_trial" || tier === "free_tier" || tier === "free") {
|
|
2225
|
+
const allowedPro = [
|
|
2226
|
+
"postgresql",
|
|
2227
|
+
"pgvector",
|
|
2228
|
+
"supabase",
|
|
2229
|
+
"pinecone",
|
|
2230
|
+
"qdrant",
|
|
2231
|
+
"mongodb",
|
|
2232
|
+
"milvus",
|
|
2233
|
+
"chroma",
|
|
2234
|
+
"chromadb"
|
|
2235
|
+
];
|
|
2236
|
+
if (!allowedPro.includes(normalizedProvider)) {
|
|
2237
|
+
throw new Error(
|
|
2238
|
+
`The database provider "${provider}" is not allowed on the Developer Pro tier. Please upgrade to an Enterprise plan.`
|
|
2239
|
+
);
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
if (licenseKey) {
|
|
2244
|
+
const cacheKey = `${licenseKey}:${currentProjectId}:${provider || ""}:${publicKeyOverride || ""}`;
|
|
2245
|
+
this.cache.set(cacheKey, { payload, cachedAt: now });
|
|
2246
|
+
}
|
|
2247
|
+
return payload;
|
|
2248
|
+
} catch (err) {
|
|
2249
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2250
|
+
throw new ConfigurationException(
|
|
2251
|
+
`[Retrivora SDK] License key validation failed: ${message}`
|
|
2252
|
+
);
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
static async verifyIP(licenseKey) {
|
|
2256
|
+
if (!licenseKey) return;
|
|
2257
|
+
try {
|
|
2258
|
+
const parts = licenseKey.split(".");
|
|
2259
|
+
if (parts.length !== 3) return;
|
|
2260
|
+
const [, payloadB64] = parts;
|
|
2261
|
+
const payload = JSON.parse(
|
|
2262
|
+
Buffer.from(payloadB64, "base64url").toString("utf8")
|
|
2263
|
+
);
|
|
2264
|
+
const tier = (payload.tier || "").toLowerCase();
|
|
2265
|
+
if (tier === "enterprise" || tier === "custom") {
|
|
2266
|
+
return;
|
|
2267
|
+
}
|
|
2268
|
+
if (payload.ipv4 || payload.ipv6) {
|
|
2269
|
+
let currentIpv4 = "";
|
|
2270
|
+
let currentIpv6 = "";
|
|
2271
|
+
try {
|
|
2272
|
+
const res = await fetch("https://api4.ipify.org?format=json", { signal: AbortSignal.timeout(3e3) });
|
|
2273
|
+
const data = await res.json();
|
|
2274
|
+
currentIpv4 = data.ip;
|
|
2275
|
+
} catch (e) {
|
|
2276
|
+
}
|
|
2277
|
+
try {
|
|
2278
|
+
const res = await fetch("https://api6.ipify.org?format=json", { signal: AbortSignal.timeout(3e3) });
|
|
2279
|
+
const data = await res.json();
|
|
2280
|
+
currentIpv6 = data.ip;
|
|
2281
|
+
} catch (e) {
|
|
2282
|
+
}
|
|
2283
|
+
const localIps = [];
|
|
2284
|
+
try {
|
|
2285
|
+
const osModule = __require("os");
|
|
2286
|
+
const interfaces = osModule.networkInterfaces();
|
|
2287
|
+
for (const name of Object.keys(interfaces)) {
|
|
2288
|
+
for (const iface of interfaces[name] || []) {
|
|
2289
|
+
if (!iface.internal) {
|
|
2290
|
+
localIps.push(iface.address);
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
} catch (e) {
|
|
2295
|
+
}
|
|
2296
|
+
const isIpv4Match = payload.ipv4 && (currentIpv4 === payload.ipv4 || localIps.includes(payload.ipv4));
|
|
2297
|
+
const isIpv6Match = payload.ipv6 && (currentIpv6 === payload.ipv6 || localIps.includes(payload.ipv6));
|
|
2298
|
+
if (payload.ipv4 && payload.ipv6) {
|
|
2299
|
+
if (!isIpv4Match && !isIpv6Match) {
|
|
2300
|
+
throw new Error(
|
|
2301
|
+
`License key access restricted. This license key was created for a different system (authorized IPv4: ${payload.ipv4}, IPv6: ${payload.ipv6}) and cannot be used on this machine.`
|
|
2302
|
+
);
|
|
2303
|
+
}
|
|
2304
|
+
} else if (payload.ipv4 && !isIpv4Match) {
|
|
2305
|
+
throw new Error(
|
|
2306
|
+
`License key access restricted. This license key was created for a different system (authorized IPv4: ${payload.ipv4}) and cannot be used on this machine.`
|
|
2307
|
+
);
|
|
2308
|
+
} else if (payload.ipv6 && !isIpv6Match) {
|
|
2309
|
+
throw new Error(
|
|
2310
|
+
`License key access restricted. This license key was created for a different system (authorized IPv6: ${payload.ipv6}) and cannot be used on this machine.`
|
|
2311
|
+
);
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
} catch (err) {
|
|
2315
|
+
if (err.message.includes("License key access restricted")) {
|
|
2316
|
+
throw new ConfigurationException(`[Retrivora SDK] ${err.message}`);
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
};
|
|
2321
|
+
// A simple in-memory cache to save CPU overhead of cryptographic signature checks.
|
|
2322
|
+
LicenseVerifier.cache = /* @__PURE__ */ new Map();
|
|
2323
|
+
LicenseVerifier.CACHE_TTL_MS = 60 * 1e3;
|
|
2324
|
+
// Cache verified license for 60 seconds
|
|
2325
|
+
// Retrivora's Public Key used to verify the license key signature.
|
|
2326
|
+
// In production, this matches the private key held by Retrivora SaaS.
|
|
2327
|
+
LicenseVerifier.PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
|
|
2328
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArMieCkCBtTfByRNOserm
|
|
2329
|
+
XM4T0Am29JyNzB4XQPe+WJJ56CN73H1HLXx9n1ByFcxkEJ9po+SURj5DnvUXwEy+
|
|
2330
|
+
xstx33wDPpVmcMQe33j5CRYS0S4gICiNqIRN7XkTlJtrcXqrmh1/hdOAwfRbjO1T
|
|
2331
|
+
NVtORHwUwWfI/lBLyxUPGtKPed+0fQ7NtcW4o00JXxs3EjCB5BV9CbnXoTjQb/4h
|
|
2332
|
+
iwZof4l8rb7oaNzOsVg0RSyxsETX7Ex5sI0CjBz1p2mYp4oVhw/A/h8Ls7H0XzjC
|
|
2333
|
+
+Eb6BLtsytt5JHoSp0jExLlCpDmpys2L+kETcBVx+IqiXtdN1n6KbkksvEDUVzLI
|
|
2334
|
+
MwIDAQAB
|
|
2335
|
+
-----END PUBLIC KEY-----`;
|
|
2336
|
+
|
|
2058
2337
|
// src/config/constants.ts
|
|
2059
2338
|
var VECTOR_DB_PROVIDERS = [
|
|
2060
2339
|
"pinecone",
|
|
@@ -2127,14 +2406,12 @@ function getRagConfig(baseConfig, env = process.env) {
|
|
|
2127
2406
|
return getEnvConfig(env, baseConfig);
|
|
2128
2407
|
}
|
|
2129
2408
|
function getEnvConfig(env = process.env, base) {
|
|
2130
|
-
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa, _ya, _za, _Aa, _Ba, _Ca, _Da, _Ea, _Fa, _Ga, _Ha, _Ia, _Ja, _Ka, _La, _Ma, _Na, _Oa, _Pa, _Qa, _Ra, _Sa, _Ta, _Ua;
|
|
2409
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa, _ya, _za, _Aa, _Ba, _Ca, _Da, _Ea, _Fa, _Ga, _Ha, _Ia, _Ja, _Ka, _La, _Ma, _Na, _Oa, _Pa, _Qa, _Ra, _Sa, _Ta, _Ua, _Va, _Wa, _Xa, _Ya, _Za, __a, _$a, _ab, _bb, _cb, _db, _eb, _fb, _gb, _hb, _ib, _jb, _kb, _lb, _mb, _nb, _ob, _pb, _qb, _rb, _sb, _tb, _ub, _vb, _wb;
|
|
2131
2410
|
const projectId = (_c = (_b = (_a2 = readString(env, "RAG_PROJECT_ID")) != null ? _a2 : readString(env, "NEXT_PUBLIC_PROJECT_ID")) != null ? _b : base == null ? void 0 : base.projectId) != null ? _c : "__default__";
|
|
2132
2411
|
const licenseKey = (_g2 = (_f = (_e = (_d = readString(env, "RAG_LICENSE_KEY")) != null ? _d : readString(env, "RETRIVORA_LICENSE_KEY")) != null ? _e : readString(env, "NEXT_PUBLIC_RETRIVORA_LICENSE_KEY")) != null ? _f : readString(env, "LICENSE_KEY")) != null ? _g2 : base == null ? void 0 : base.licenseKey;
|
|
2133
2412
|
const telemetryEnabled = readString(env, "TELEMETRY_ENABLED") === "true" || readString(env, "NEXT_PUBLIC_TELEMETRY_ENABLED") === "true" || ((_h = base == null ? void 0 : base.telemetry) == null ? void 0 : _h.enabled) || Boolean(licenseKey);
|
|
2134
2413
|
const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
|
|
2135
|
-
const
|
|
2136
|
-
const embeddingProvider = readEnum(env, "EMBEDDING_PROVIDER", "openai", EMBEDDING_PROVIDERS);
|
|
2137
|
-
const embeddingDimensions = readNumber(env, "EMBEDDING_DIMENSIONS", 1536);
|
|
2414
|
+
const embeddingDimensions = readNumber(env, "EMBEDDING_DIMENSIONS", 768);
|
|
2138
2415
|
const vectorDbOptions = {};
|
|
2139
2416
|
if (vectorProvider === "pinecone") {
|
|
2140
2417
|
vectorDbOptions.apiKey = (_l = (_k = readString(env, "PINECONE_API_KEY")) != null ? _k : (_j = (_i = base == null ? void 0 : base.vectorDb) == null ? void 0 : _i.options) == null ? void 0 : _j.apiKey) != null ? _l : "";
|
|
@@ -2199,65 +2476,88 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2199
2476
|
rest: "default",
|
|
2200
2477
|
custom: "default"
|
|
2201
2478
|
};
|
|
2479
|
+
const isFreeTier = (() => {
|
|
2480
|
+
if (!licenseKey) return true;
|
|
2481
|
+
try {
|
|
2482
|
+
const payload = LicenseVerifier.verify(licenseKey, projectId);
|
|
2483
|
+
const tier = (payload.tier || "").toLowerCase();
|
|
2484
|
+
return tier === "free_trial" || tier === "free_tier" || tier === "free" || tier === "hobby";
|
|
2485
|
+
} catch (e) {
|
|
2486
|
+
return true;
|
|
2487
|
+
}
|
|
2488
|
+
})();
|
|
2489
|
+
const DEFAULT_FREE_GATEWAY = "https://llm.retrivora.com/api/v1";
|
|
2490
|
+
const defaultLlmProvider = isFreeTier ? "universal_rest" : "universal_rest";
|
|
2491
|
+
const llmProvider = (_na = (_ma = readEnum(env, "LLM_PROVIDER", defaultLlmProvider, LLM_PROVIDERS)) != null ? _ma : (_la = base == null ? void 0 : base.llm) == null ? void 0 : _la.provider) != null ? _na : defaultLlmProvider;
|
|
2492
|
+
const llmBaseUrl = (_qa = (_pa = readString(env, "LLM_BASE_URL")) != null ? _pa : (_oa = base == null ? void 0 : base.llm) == null ? void 0 : _oa.baseUrl) != null ? _qa : DEFAULT_FREE_GATEWAY;
|
|
2493
|
+
const llmModel = (_ua = (_sa = readString(env, "LLM_MODEL")) != null ? _sa : (_ra = base == null ? void 0 : base.llm) == null ? void 0 : _ra.model) != null ? _ua : isFreeTier ? "llama-3.1-8b-instant" : (_ta = DEFAULT_MODEL_BY_PROVIDER[llmProvider]) != null ? _ta : "gpt-4o";
|
|
2494
|
+
const llmApiKey = (_ya = (_xa = (_va = llmApiKeyByProvider[llmProvider]) != null ? _va : readString(env, "LLM_API_KEY")) != null ? _xa : (_wa = base == null ? void 0 : base.llm) == null ? void 0 : _wa.apiKey) != null ? _ya : "sk-retrivora-cancer-280590";
|
|
2495
|
+
const llmProfile = (_Ca = (_Ba = readString(env, "LLM_UNIVERSAL_PROFILE")) != null ? _Ba : (_Aa = (_za = base == null ? void 0 : base.llm) == null ? void 0 : _za.options) == null ? void 0 : _Aa.profile) != null ? _Ca : "litellm";
|
|
2496
|
+
const defaultEmbeddingProvider = isFreeTier ? "universal_rest" : "universal_rest";
|
|
2497
|
+
const embeddingProvider = (_Fa = (_Ea = readEnum(env, "EMBEDDING_PROVIDER", defaultEmbeddingProvider, EMBEDDING_PROVIDERS)) != null ? _Ea : (_Da = base == null ? void 0 : base.embedding) == null ? void 0 : _Da.provider) != null ? _Fa : defaultEmbeddingProvider;
|
|
2498
|
+
const embeddingBaseUrl = (_Ia = (_Ha = readString(env, "EMBEDDING_BASE_URL")) != null ? _Ha : (_Ga = base == null ? void 0 : base.embedding) == null ? void 0 : _Ga.baseUrl) != null ? _Ia : DEFAULT_FREE_GATEWAY;
|
|
2499
|
+
const embeddingModel = (_La = (_Ka = readString(env, "EMBEDDING_MODEL")) != null ? _Ka : (_Ja = base == null ? void 0 : base.embedding) == null ? void 0 : _Ja.model) != null ? _La : "text-embedding-004";
|
|
2500
|
+
const embeddingApiKey = (_Qa = (_Pa = (_Na = (_Ma = embeddingApiKeyByProvider[embeddingProvider]) != null ? _Ma : readString(env, "EMBEDDING_API_KEY")) != null ? _Na : readString(env, "LLM_API_KEY")) != null ? _Pa : (_Oa = base == null ? void 0 : base.embedding) == null ? void 0 : _Oa.apiKey) != null ? _Qa : "sk-retrivora-cancer-280590";
|
|
2501
|
+
const embeddingProfile = (_Ua = (_Ta = readString(env, "EMBEDDING_UNIVERSAL_PROFILE")) != null ? _Ta : (_Sa = (_Ra = base == null ? void 0 : base.embedding) == null ? void 0 : _Ra.options) == null ? void 0 : _Sa.profile) != null ? _Ua : "litellm";
|
|
2202
2502
|
return __spreadProps(__spreadValues({
|
|
2203
2503
|
projectId,
|
|
2204
|
-
licenseKey
|
|
2504
|
+
licenseKey,
|
|
2205
2505
|
vectorDb: {
|
|
2206
2506
|
provider: vectorProvider,
|
|
2207
|
-
indexName: (
|
|
2507
|
+
indexName: (_Wa = (_Va = readString(env, "VECTOR_DB_INDEX")) != null ? _Va : vectorDbOptions.indexName) != null ? _Wa : "rag-index",
|
|
2208
2508
|
options: vectorDbOptions
|
|
2209
2509
|
},
|
|
2210
2510
|
llm: {
|
|
2211
2511
|
provider: llmProvider,
|
|
2212
|
-
model:
|
|
2213
|
-
apiKey:
|
|
2214
|
-
baseUrl:
|
|
2512
|
+
model: llmModel,
|
|
2513
|
+
apiKey: llmApiKey,
|
|
2514
|
+
baseUrl: llmBaseUrl,
|
|
2215
2515
|
systemPrompt: readString(env, "LLM_SYSTEM_PROMPT"),
|
|
2216
2516
|
maxTokens: readNumber(env, "LLM_MAX_TOKENS", 4096),
|
|
2217
2517
|
temperature: readNumber(env, "LLM_TEMPERATURE", 0.7),
|
|
2218
2518
|
options: {
|
|
2219
|
-
profile:
|
|
2519
|
+
profile: llmProfile,
|
|
2220
2520
|
thinking: readString(env, "LLM_THINKING") === "true" || readString(env, "LLM_THINKING") === "enabled" ? true : readString(env, "LLM_THINKING") === "false" ? false : void 0,
|
|
2221
2521
|
thinkingBudget: env.LLM_THINKING_BUDGET ? parseInt(env.LLM_THINKING_BUDGET, 10) : void 0
|
|
2222
2522
|
}
|
|
2223
2523
|
},
|
|
2224
2524
|
embedding: {
|
|
2225
2525
|
provider: embeddingProvider,
|
|
2226
|
-
model:
|
|
2227
|
-
apiKey:
|
|
2228
|
-
baseUrl:
|
|
2526
|
+
model: embeddingModel,
|
|
2527
|
+
apiKey: embeddingApiKey,
|
|
2528
|
+
baseUrl: embeddingBaseUrl,
|
|
2229
2529
|
dimensions: embeddingDimensions,
|
|
2230
2530
|
queryPrefix: readString(env, "EMBEDDING_QUERY_PREFIX"),
|
|
2231
2531
|
documentPrefix: readString(env, "EMBEDDING_DOCUMENT_PREFIX"),
|
|
2232
2532
|
options: {
|
|
2233
|
-
profile:
|
|
2533
|
+
profile: embeddingProfile
|
|
2234
2534
|
}
|
|
2235
2535
|
},
|
|
2236
2536
|
ui: {
|
|
2237
|
-
title: (
|
|
2238
|
-
subtitle: (
|
|
2239
|
-
primaryColor: (
|
|
2240
|
-
accentColor: (
|
|
2241
|
-
logoUrl: (
|
|
2242
|
-
placeholder: (
|
|
2243
|
-
showSources: ((
|
|
2244
|
-
welcomeMessage: (
|
|
2245
|
-
visualStyle: (
|
|
2246
|
-
borderRadius: (
|
|
2247
|
-
allowUpload: ((
|
|
2537
|
+
title: (_Ya = (_Xa = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _Xa : readString(env, "UI_TITLE")) != null ? _Ya : "AI Assistant",
|
|
2538
|
+
subtitle: (__a = (_Za = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _Za : readString(env, "UI_SUBTITLE")) != null ? __a : "Powered by RAG",
|
|
2539
|
+
primaryColor: (_ab = (_$a = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _$a : readString(env, "UI_PRIMARY_COLOR")) != null ? _ab : "#10b981",
|
|
2540
|
+
accentColor: (_cb = (_bb = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _bb : readString(env, "UI_ACCENT_COLOR")) != null ? _cb : "#3b82f6",
|
|
2541
|
+
logoUrl: (_db = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _db : readString(env, "UI_LOGO_URL"),
|
|
2542
|
+
placeholder: (_fb = (_eb = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _eb : readString(env, "UI_PLACEHOLDER")) != null ? _fb : "Ask me anything\u2026",
|
|
2543
|
+
showSources: ((_hb = (_gb = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _gb : readString(env, "UI_SHOW_SOURCES")) != null ? _hb : "true") !== "false",
|
|
2544
|
+
welcomeMessage: (_jb = (_ib = readString(env, "NEXT_PUBLIC_WELCOME_MESSAGE")) != null ? _ib : readString(env, "UI_WELCOME_MESSAGE")) != null ? _jb : "Hello! I'm your AI assistant. Ask me anything about your documents.",
|
|
2545
|
+
visualStyle: (_lb = (_kb = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _kb : readString(env, "UI_VISUAL_STYLE")) != null ? _lb : "glass",
|
|
2546
|
+
borderRadius: (_nb = (_mb = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _mb : readString(env, "UI_BORDER_RADIUS")) != null ? _nb : "xl",
|
|
2547
|
+
allowUpload: ((_pb = (_ob = readString(env, "NEXT_PUBLIC_ALLOW_UPLOAD")) != null ? _ob : readString(env, "UI_ALLOW_UPLOAD")) != null ? _pb : "false") === "true"
|
|
2248
2548
|
},
|
|
2249
2549
|
rag: {
|
|
2250
2550
|
topK: readNumber(env, "RAG_TOP_K", 5),
|
|
2251
2551
|
scoreThreshold: readNumber(env, "RAG_SCORE_THRESHOLD", 0),
|
|
2252
2552
|
chunkSize: readNumber(env, "RAG_CHUNK_SIZE", 1e3),
|
|
2253
2553
|
chunkOverlap: readNumber(env, "RAG_CHUNK_OVERLAP", 200),
|
|
2254
|
-
filterableFields: (
|
|
2554
|
+
filterableFields: (_qb = readString(env, "RAG_FILTERABLE_FIELDS")) == null ? void 0 : _qb.split(",").map((f) => f.trim()),
|
|
2255
2555
|
// Query pipeline toggles — read from .env.local
|
|
2256
2556
|
useQueryTransformation: readString(env, "RAG_USE_QUERY_TRANSFORMATION") === "true",
|
|
2257
2557
|
useReranking: readString(env, "RAG_USE_RERANKING") === "true",
|
|
2258
2558
|
useGraphRetrieval: readString(env, "RAG_USE_GRAPH_RETRIEVAL") === "true",
|
|
2259
|
-
architecture: (
|
|
2260
|
-
chunkingStrategy: (
|
|
2559
|
+
architecture: (_rb = readString(env, "RAG_ARCHITECTURE")) != null ? _rb : "simple",
|
|
2560
|
+
chunkingStrategy: (_sb = readString(env, "RAG_CHUNKING_STRATEGY")) != null ? _sb : "recursive",
|
|
2261
2561
|
uiMapping: (() => {
|
|
2262
2562
|
const raw = readString(env, "RAG_UI_MAPPING");
|
|
2263
2563
|
if (!raw) return void 0;
|
|
@@ -2270,7 +2570,7 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2270
2570
|
},
|
|
2271
2571
|
telemetry: {
|
|
2272
2572
|
enabled: telemetryEnabled,
|
|
2273
|
-
url: (
|
|
2573
|
+
url: (_wb = (_vb = (_tb = readString(env, "TELEMETRY_URL")) != null ? _tb : readString(env, "NEXT_PUBLIC_TELEMETRY_URL")) != null ? _vb : (_ub = base == null ? void 0 : base.telemetry) == null ? void 0 : _ub.url) != null ? _wb : process.env.NODE_ENV === "development" ? "http://localhost:3001/api/telemetry" : "https://retrivora.com/api/telemetry"
|
|
2274
2574
|
}
|
|
2275
2575
|
}, readString(env, "GRAPH_DB_PROVIDER") ? {
|
|
2276
2576
|
graphDb: {
|
|
@@ -2757,10 +3057,12 @@ var AnthropicProvider = class {
|
|
|
2757
3057
|
import axios from "axios";
|
|
2758
3058
|
var OllamaProvider = class {
|
|
2759
3059
|
constructor(llmConfig, embeddingConfig) {
|
|
2760
|
-
var _a2, _b;
|
|
2761
|
-
const
|
|
3060
|
+
var _a2, _b, _c;
|
|
3061
|
+
const rawBaseURL = ((_a2 = llmConfig.baseUrl) != null ? _a2 : "http://localhost:11434").replace(/\/+$/, "");
|
|
3062
|
+
const baseURL = rawBaseURL.replace(/\/(?:api\/v1|v1|api)$/i, "");
|
|
2762
3063
|
const timeout = Number((_b = llmConfig.options) == null ? void 0 : _b.timeout) || 3e5;
|
|
2763
|
-
|
|
3064
|
+
const headers = ((_c = llmConfig.options) == null ? void 0 : _c.headers) || {};
|
|
3065
|
+
this.http = axios.create({ baseURL, timeout, headers });
|
|
2764
3066
|
this.llmConfig = llmConfig;
|
|
2765
3067
|
this.embeddingConfig = embeddingConfig;
|
|
2766
3068
|
}
|
|
@@ -3609,7 +3911,7 @@ var UniversalLLMAdapter = class {
|
|
|
3609
3911
|
});
|
|
3610
3912
|
}
|
|
3611
3913
|
async chat(messages, context) {
|
|
3612
|
-
var _a2, _b;
|
|
3914
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3613
3915
|
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3614
3916
|
const formattedMessages = [
|
|
3615
3917
|
{ role: "system", content: `${this.systemPrompt}
|
|
@@ -3634,8 +3936,26 @@ ${context != null ? context : "None"}` },
|
|
|
3634
3936
|
temperature: this.temperature
|
|
3635
3937
|
};
|
|
3636
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
|
+
}
|
|
3637
3957
|
const { data } = await this.http.post(path2, payload);
|
|
3638
|
-
const extractPath = (
|
|
3958
|
+
const extractPath = (_f = this.opts.responseExtractPath) != null ? _f : "choices[0].message.content";
|
|
3639
3959
|
const result = resolvePath(data, extractPath);
|
|
3640
3960
|
if (result === void 0) {
|
|
3641
3961
|
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
@@ -3649,7 +3969,7 @@ ${context != null ? context : "None"}` },
|
|
|
3649
3969
|
*/
|
|
3650
3970
|
chatStream(messages, context) {
|
|
3651
3971
|
return __asyncGenerator(this, null, function* () {
|
|
3652
|
-
var _a2, _b, _c;
|
|
3972
|
+
var _a2, _b, _c, _d, _e, _f, _g2;
|
|
3653
3973
|
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3654
3974
|
const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
|
|
3655
3975
|
const extractPath = ((_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content").replace("message.content", "delta.content");
|
|
@@ -3680,19 +4000,45 @@ ${context != null ? context : "None"}` },
|
|
|
3680
4000
|
stream: true
|
|
3681
4001
|
};
|
|
3682
4002
|
}
|
|
3683
|
-
const
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
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
|
+
}
|
|
3691
4025
|
}
|
|
3692
|
-
if (!
|
|
3693
|
-
|
|
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;
|
|
3694
4040
|
}
|
|
3695
|
-
const reader =
|
|
4041
|
+
const reader = streamBody.getReader();
|
|
3696
4042
|
const decoder = new TextDecoder("utf-8");
|
|
3697
4043
|
let buffer = "";
|
|
3698
4044
|
try {
|
|
@@ -3701,7 +4047,7 @@ ${context != null ? context : "None"}` },
|
|
|
3701
4047
|
if (done) break;
|
|
3702
4048
|
buffer += decoder.decode(value, { stream: true });
|
|
3703
4049
|
const lines = buffer.split("\n");
|
|
3704
|
-
buffer = (
|
|
4050
|
+
buffer = (_g2 = lines.pop()) != null ? _g2 : "";
|
|
3705
4051
|
for (const line of lines) {
|
|
3706
4052
|
const trimmed = line.trim();
|
|
3707
4053
|
if (!trimmed || trimmed === "data: [DONE]") continue;
|
|
@@ -3729,7 +4075,7 @@ ${context != null ? context : "None"}` },
|
|
|
3729
4075
|
});
|
|
3730
4076
|
}
|
|
3731
4077
|
async embed(text) {
|
|
3732
|
-
var _a2, _b;
|
|
4078
|
+
var _a2, _b, _c, _d;
|
|
3733
4079
|
const path2 = (_a2 = this.opts.embedPath) != null ? _a2 : "/embeddings";
|
|
3734
4080
|
let payload;
|
|
3735
4081
|
if (this.opts.embedPayloadTemplate) {
|
|
@@ -3743,105 +4089,49 @@ ${context != null ? context : "None"}` },
|
|
|
3743
4089
|
input: text
|
|
3744
4090
|
};
|
|
3745
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
|
+
}
|
|
3746
4108
|
const { data } = await this.http.post(path2, payload);
|
|
3747
|
-
const extractPath = (
|
|
4109
|
+
const extractPath = (_d = this.opts.embedExtractPath) != null ? _d : "data[0].embedding";
|
|
3748
4110
|
const vector = resolvePath(data, extractPath);
|
|
3749
4111
|
if (!Array.isArray(vector)) {
|
|
3750
4112
|
throw new Error(`[UniversalLLMAdapter] Expected a number array at '${extractPath}' for embeddings.`);
|
|
3751
4113
|
}
|
|
3752
4114
|
return vector;
|
|
3753
4115
|
}
|
|
3754
|
-
async batchEmbed(texts) {
|
|
3755
|
-
const vectors = [];
|
|
3756
|
-
for (const text of texts) {
|
|
3757
|
-
vectors.push(await this.embed(text));
|
|
3758
|
-
}
|
|
3759
|
-
return vectors;
|
|
3760
|
-
}
|
|
3761
|
-
async ping() {
|
|
3762
|
-
try {
|
|
3763
|
-
if (this.opts.pingPath) {
|
|
3764
|
-
await this.http.get(this.opts.pingPath);
|
|
3765
|
-
}
|
|
3766
|
-
return true;
|
|
3767
|
-
} catch (err) {
|
|
3768
|
-
console.error("[UniversalLLMAdapter] Ping failed:", err);
|
|
3769
|
-
return false;
|
|
3770
|
-
}
|
|
3771
|
-
}
|
|
3772
|
-
};
|
|
3773
|
-
|
|
3774
|
-
// src/exceptions/index.ts
|
|
3775
|
-
var RetrivoraError = class extends Error {
|
|
3776
|
-
constructor(message, code, details) {
|
|
3777
|
-
super(message);
|
|
3778
|
-
this.name = new.target.name;
|
|
3779
|
-
this.code = code;
|
|
3780
|
-
this.details = details;
|
|
3781
|
-
}
|
|
3782
|
-
};
|
|
3783
|
-
var ProviderNotFoundException = class extends RetrivoraError {
|
|
3784
|
-
constructor(providerType, provider, details) {
|
|
3785
|
-
super(`Unsupported ${providerType} provider: ${provider}`, "PROVIDER_NOT_FOUND", details);
|
|
3786
|
-
}
|
|
3787
|
-
};
|
|
3788
|
-
var EmbeddingFailedException = class extends RetrivoraError {
|
|
3789
|
-
constructor(message = "Embedding generation failed", details) {
|
|
3790
|
-
super(message, "EMBEDDING_FAILED", details);
|
|
3791
|
-
}
|
|
3792
|
-
};
|
|
3793
|
-
var RetrievalException = class extends RetrivoraError {
|
|
3794
|
-
constructor(message = "Retrieval failed", details) {
|
|
3795
|
-
super(message, "RETRIEVAL_FAILED", details);
|
|
3796
|
-
}
|
|
3797
|
-
};
|
|
3798
|
-
var RateLimitException = class extends RetrivoraError {
|
|
3799
|
-
constructor(message = "Provider rate limit exceeded", details) {
|
|
3800
|
-
super(message, "RATE_LIMITED", details);
|
|
3801
|
-
}
|
|
3802
|
-
};
|
|
3803
|
-
var ConfigurationException = class extends RetrivoraError {
|
|
3804
|
-
constructor(message, details) {
|
|
3805
|
-
super(message, "CONFIGURATION_ERROR", details);
|
|
3806
|
-
}
|
|
3807
|
-
};
|
|
3808
|
-
var AuthenticationException = class extends RetrivoraError {
|
|
3809
|
-
constructor(message = "Provider authentication failed", details) {
|
|
3810
|
-
super(message, "AUTHENTICATION_ERROR", details);
|
|
3811
|
-
}
|
|
3812
|
-
};
|
|
3813
|
-
function wrapError(err, defaultCode, defaultMessage) {
|
|
3814
|
-
var _a2;
|
|
3815
|
-
if (err instanceof RetrivoraError) {
|
|
3816
|
-
return err;
|
|
3817
|
-
}
|
|
3818
|
-
const error = err;
|
|
3819
|
-
const message = (error == null ? void 0 : error.message) || defaultMessage || String(err);
|
|
3820
|
-
const status = (error == null ? void 0 : error.status) || (error == null ? void 0 : error.statusCode) || ((_a2 = error == null ? void 0 : error.response) == null ? void 0 : _a2.status);
|
|
3821
|
-
const code = error == null ? void 0 : error.code;
|
|
3822
|
-
if (status === 429 || /rate[- ]?limit/i.test(message) || code === "RATE_LIMIT_EXCEEDED") {
|
|
3823
|
-
return new RateLimitException(message, err);
|
|
3824
|
-
}
|
|
3825
|
-
if (status === 401 || status === 403 || /unauthorized|auth|api[- ]?key/i.test(message) || code === "INVALID_API_KEY") {
|
|
3826
|
-
return new AuthenticationException(message, err);
|
|
4116
|
+
async batchEmbed(texts) {
|
|
4117
|
+
const vectors = [];
|
|
4118
|
+
for (const text of texts) {
|
|
4119
|
+
vectors.push(await this.embed(text));
|
|
4120
|
+
}
|
|
4121
|
+
return vectors;
|
|
3827
4122
|
}
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
return
|
|
3837
|
-
|
|
3838
|
-
return new ConfigurationException(message, err);
|
|
3839
|
-
case "AUTHENTICATION_ERROR":
|
|
3840
|
-
return new AuthenticationException(message, err);
|
|
3841
|
-
default:
|
|
3842
|
-
return new RetrivoraError(message, defaultCode, err);
|
|
4123
|
+
async ping() {
|
|
4124
|
+
try {
|
|
4125
|
+
if (this.opts.pingPath) {
|
|
4126
|
+
await this.http.get(this.opts.pingPath);
|
|
4127
|
+
}
|
|
4128
|
+
return true;
|
|
4129
|
+
} catch (err) {
|
|
4130
|
+
console.error("[UniversalLLMAdapter] Ping failed:", err);
|
|
4131
|
+
return false;
|
|
4132
|
+
}
|
|
3843
4133
|
}
|
|
3844
|
-
}
|
|
4134
|
+
};
|
|
3845
4135
|
|
|
3846
4136
|
// src/llm/LLMFactory.ts
|
|
3847
4137
|
var customProviders = /* @__PURE__ */ new Map();
|
|
@@ -4240,211 +4530,6 @@ var ConfigValidator = class {
|
|
|
4240
4530
|
}
|
|
4241
4531
|
};
|
|
4242
4532
|
|
|
4243
|
-
// src/core/LicenseVerifier.ts
|
|
4244
|
-
import * as crypto2 from "crypto";
|
|
4245
|
-
var LicenseVerifier = class {
|
|
4246
|
-
/**
|
|
4247
|
-
* Decodes, verifies signature, and checks metadata of a license key.
|
|
4248
|
-
*
|
|
4249
|
-
* @param licenseKey - Base64url signed JWT license key.
|
|
4250
|
-
* @param currentProjectId - Project namespace ID.
|
|
4251
|
-
* @param publicKeyOverride - Optional override for unit/integration tests.
|
|
4252
|
-
*/
|
|
4253
|
-
static verify(licenseKey, currentProjectId, provider, publicKeyOverride) {
|
|
4254
|
-
const isProduction = process.env.NODE_ENV === "production";
|
|
4255
|
-
const now = Date.now();
|
|
4256
|
-
if (licenseKey) {
|
|
4257
|
-
const cacheKey = `${licenseKey}:${currentProjectId}:${provider || ""}:${publicKeyOverride || ""}`;
|
|
4258
|
-
const cached = this.cache.get(cacheKey);
|
|
4259
|
-
if (cached && now - cached.cachedAt < this.CACHE_TTL_MS) {
|
|
4260
|
-
const currentTimestampSec = Math.floor(now / 1e3);
|
|
4261
|
-
if (cached.payload.expiresAt && currentTimestampSec > cached.payload.expiresAt) {
|
|
4262
|
-
this.cache.delete(cacheKey);
|
|
4263
|
-
} else {
|
|
4264
|
-
return cached.payload;
|
|
4265
|
-
}
|
|
4266
|
-
}
|
|
4267
|
-
}
|
|
4268
|
-
if (!licenseKey) {
|
|
4269
|
-
if (isProduction) {
|
|
4270
|
-
throw new ConfigurationException(
|
|
4271
|
-
"[Retrivora SDK] License key (licenseKey) is required in production environments."
|
|
4272
|
-
);
|
|
4273
|
-
}
|
|
4274
|
-
console.warn(
|
|
4275
|
-
`\x1B[33m[Retrivora SDK] WARNING: Running without a license key. This namespace (${currentProjectId}) is permitted for local development only.\x1B[0m`
|
|
4276
|
-
);
|
|
4277
|
-
return {
|
|
4278
|
-
projectId: currentProjectId,
|
|
4279
|
-
expiresAt: Math.floor(Date.now() / 1e3) + 86400,
|
|
4280
|
-
// Valid for 24h
|
|
4281
|
-
tier: "hobby"
|
|
4282
|
-
};
|
|
4283
|
-
}
|
|
4284
|
-
try {
|
|
4285
|
-
const parts = licenseKey.split(".");
|
|
4286
|
-
if (parts.length !== 3) {
|
|
4287
|
-
throw new Error("Malformed token structure (expected 3 parts).");
|
|
4288
|
-
}
|
|
4289
|
-
const [headerB64, payloadB64, signatureB64] = parts;
|
|
4290
|
-
const dataToVerify = `${headerB64}.${payloadB64}`;
|
|
4291
|
-
const publicKey = publicKeyOverride != null ? publicKeyOverride : this.PUBLIC_KEY;
|
|
4292
|
-
const signature = Buffer.from(signatureB64, "base64url");
|
|
4293
|
-
const data = Buffer.from(dataToVerify);
|
|
4294
|
-
const isValid = crypto2.verify(
|
|
4295
|
-
"sha256",
|
|
4296
|
-
data,
|
|
4297
|
-
publicKey,
|
|
4298
|
-
signature
|
|
4299
|
-
);
|
|
4300
|
-
if (!isValid) {
|
|
4301
|
-
throw new Error("Signature verification failed.");
|
|
4302
|
-
}
|
|
4303
|
-
const payload = JSON.parse(
|
|
4304
|
-
Buffer.from(payloadB64, "base64url").toString("utf8")
|
|
4305
|
-
);
|
|
4306
|
-
if (!payload.projectId) {
|
|
4307
|
-
throw new Error('License payload is missing "projectId".');
|
|
4308
|
-
}
|
|
4309
|
-
if (payload.projectId !== currentProjectId) {
|
|
4310
|
-
throw new Error(
|
|
4311
|
-
`Project ID mismatch. License is bound to project namespace "${payload.projectId}" but configuration has "${currentProjectId}".`
|
|
4312
|
-
);
|
|
4313
|
-
}
|
|
4314
|
-
if (!payload.expiresAt) {
|
|
4315
|
-
throw new Error('License payload is missing expiration ("expiresAt").');
|
|
4316
|
-
}
|
|
4317
|
-
const currentTimestampSec = Math.floor(Date.now() / 1e3);
|
|
4318
|
-
if (currentTimestampSec > payload.expiresAt) {
|
|
4319
|
-
throw new Error(
|
|
4320
|
-
`License key has expired. Expiration: ${new Date(
|
|
4321
|
-
payload.expiresAt * 1e3
|
|
4322
|
-
).toDateString()}`
|
|
4323
|
-
);
|
|
4324
|
-
}
|
|
4325
|
-
if (isProduction && provider) {
|
|
4326
|
-
const tier = (payload.tier || "").toLowerCase();
|
|
4327
|
-
const normalizedProvider = provider.toLowerCase();
|
|
4328
|
-
if (tier === "hobby") {
|
|
4329
|
-
const allowedHobby = ["postgresql", "pgvector", "supabase"];
|
|
4330
|
-
if (!allowedHobby.includes(normalizedProvider)) {
|
|
4331
|
-
throw new Error(
|
|
4332
|
-
`The database provider "${provider}" is not allowed on the Hobby tier. Hobby tier is restricted to PostgreSQL and Supabase. Please upgrade to a Developer Pro or Enterprise plan.`
|
|
4333
|
-
);
|
|
4334
|
-
}
|
|
4335
|
-
} else if (tier === "pro" || tier === "developer_pro" || tier === "premium" || tier === "growth" || tier === "free_trial" || tier === "free_tier" || tier === "free") {
|
|
4336
|
-
const allowedPro = [
|
|
4337
|
-
"postgresql",
|
|
4338
|
-
"pgvector",
|
|
4339
|
-
"supabase",
|
|
4340
|
-
"pinecone",
|
|
4341
|
-
"qdrant",
|
|
4342
|
-
"mongodb",
|
|
4343
|
-
"milvus",
|
|
4344
|
-
"chroma",
|
|
4345
|
-
"chromadb"
|
|
4346
|
-
];
|
|
4347
|
-
if (!allowedPro.includes(normalizedProvider)) {
|
|
4348
|
-
throw new Error(
|
|
4349
|
-
`The database provider "${provider}" is not allowed on the Developer Pro tier. Please upgrade to an Enterprise plan.`
|
|
4350
|
-
);
|
|
4351
|
-
}
|
|
4352
|
-
}
|
|
4353
|
-
}
|
|
4354
|
-
if (licenseKey) {
|
|
4355
|
-
const cacheKey = `${licenseKey}:${currentProjectId}:${provider || ""}:${publicKeyOverride || ""}`;
|
|
4356
|
-
this.cache.set(cacheKey, { payload, cachedAt: now });
|
|
4357
|
-
}
|
|
4358
|
-
return payload;
|
|
4359
|
-
} catch (err) {
|
|
4360
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
4361
|
-
throw new ConfigurationException(
|
|
4362
|
-
`[Retrivora SDK] License key validation failed: ${message}`
|
|
4363
|
-
);
|
|
4364
|
-
}
|
|
4365
|
-
}
|
|
4366
|
-
static async verifyIP(licenseKey) {
|
|
4367
|
-
if (!licenseKey) return;
|
|
4368
|
-
try {
|
|
4369
|
-
const parts = licenseKey.split(".");
|
|
4370
|
-
if (parts.length !== 3) return;
|
|
4371
|
-
const [, payloadB64] = parts;
|
|
4372
|
-
const payload = JSON.parse(
|
|
4373
|
-
Buffer.from(payloadB64, "base64url").toString("utf8")
|
|
4374
|
-
);
|
|
4375
|
-
const tier = (payload.tier || "").toLowerCase();
|
|
4376
|
-
if (tier === "enterprise" || tier === "custom") {
|
|
4377
|
-
return;
|
|
4378
|
-
}
|
|
4379
|
-
if (payload.ipv4 || payload.ipv6) {
|
|
4380
|
-
let currentIpv4 = "";
|
|
4381
|
-
let currentIpv6 = "";
|
|
4382
|
-
try {
|
|
4383
|
-
const res = await fetch("https://api4.ipify.org?format=json", { signal: AbortSignal.timeout(3e3) });
|
|
4384
|
-
const data = await res.json();
|
|
4385
|
-
currentIpv4 = data.ip;
|
|
4386
|
-
} catch (e) {
|
|
4387
|
-
}
|
|
4388
|
-
try {
|
|
4389
|
-
const res = await fetch("https://api6.ipify.org?format=json", { signal: AbortSignal.timeout(3e3) });
|
|
4390
|
-
const data = await res.json();
|
|
4391
|
-
currentIpv6 = data.ip;
|
|
4392
|
-
} catch (e) {
|
|
4393
|
-
}
|
|
4394
|
-
const localIps = [];
|
|
4395
|
-
try {
|
|
4396
|
-
const osModule = __require("os");
|
|
4397
|
-
const interfaces = osModule.networkInterfaces();
|
|
4398
|
-
for (const name of Object.keys(interfaces)) {
|
|
4399
|
-
for (const iface of interfaces[name] || []) {
|
|
4400
|
-
if (!iface.internal) {
|
|
4401
|
-
localIps.push(iface.address);
|
|
4402
|
-
}
|
|
4403
|
-
}
|
|
4404
|
-
}
|
|
4405
|
-
} catch (e) {
|
|
4406
|
-
}
|
|
4407
|
-
const isIpv4Match = payload.ipv4 && (currentIpv4 === payload.ipv4 || localIps.includes(payload.ipv4));
|
|
4408
|
-
const isIpv6Match = payload.ipv6 && (currentIpv6 === payload.ipv6 || localIps.includes(payload.ipv6));
|
|
4409
|
-
if (payload.ipv4 && payload.ipv6) {
|
|
4410
|
-
if (!isIpv4Match && !isIpv6Match) {
|
|
4411
|
-
throw new Error(
|
|
4412
|
-
`License key access restricted. This license key was created for a different system (authorized IPv4: ${payload.ipv4}, IPv6: ${payload.ipv6}) and cannot be used on this machine.`
|
|
4413
|
-
);
|
|
4414
|
-
}
|
|
4415
|
-
} else if (payload.ipv4 && !isIpv4Match) {
|
|
4416
|
-
throw new Error(
|
|
4417
|
-
`License key access restricted. This license key was created for a different system (authorized IPv4: ${payload.ipv4}) and cannot be used on this machine.`
|
|
4418
|
-
);
|
|
4419
|
-
} else if (payload.ipv6 && !isIpv6Match) {
|
|
4420
|
-
throw new Error(
|
|
4421
|
-
`License key access restricted. This license key was created for a different system (authorized IPv6: ${payload.ipv6}) and cannot be used on this machine.`
|
|
4422
|
-
);
|
|
4423
|
-
}
|
|
4424
|
-
}
|
|
4425
|
-
} catch (err) {
|
|
4426
|
-
if (err.message.includes("License key access restricted")) {
|
|
4427
|
-
throw new ConfigurationException(`[Retrivora SDK] ${err.message}`);
|
|
4428
|
-
}
|
|
4429
|
-
}
|
|
4430
|
-
}
|
|
4431
|
-
};
|
|
4432
|
-
// A simple in-memory cache to save CPU overhead of cryptographic signature checks.
|
|
4433
|
-
LicenseVerifier.cache = /* @__PURE__ */ new Map();
|
|
4434
|
-
LicenseVerifier.CACHE_TTL_MS = 60 * 1e3;
|
|
4435
|
-
// Cache verified license for 60 seconds
|
|
4436
|
-
// Retrivora's Public Key used to verify the license key signature.
|
|
4437
|
-
// In production, this matches the private key held by Retrivora SaaS.
|
|
4438
|
-
LicenseVerifier.PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
|
|
4439
|
-
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArMieCkCBtTfByRNOserm
|
|
4440
|
-
XM4T0Am29JyNzB4XQPe+WJJ56CN73H1HLXx9n1ByFcxkEJ9po+SURj5DnvUXwEy+
|
|
4441
|
-
xstx33wDPpVmcMQe33j5CRYS0S4gICiNqIRN7XkTlJtrcXqrmh1/hdOAwfRbjO1T
|
|
4442
|
-
NVtORHwUwWfI/lBLyxUPGtKPed+0fQ7NtcW4o00JXxs3EjCB5BV9CbnXoTjQb/4h
|
|
4443
|
-
iwZof4l8rb7oaNzOsVg0RSyxsETX7Ex5sI0CjBz1p2mYp4oVhw/A/h8Ls7H0XzjC
|
|
4444
|
-
+Eb6BLtsytt5JHoSp0jExLlCpDmpys2L+kETcBVx+IqiXtdN1n6KbkksvEDUVzLI
|
|
4445
|
-
MwIDAQAB
|
|
4446
|
-
-----END PUBLIC KEY-----`;
|
|
4447
|
-
|
|
4448
4533
|
// src/rag/DocumentChunker.ts
|
|
4449
4534
|
var DocumentChunker = class {
|
|
4450
4535
|
constructor(chunkSize = 1e3, chunkOverlap = 200, separators = ["\n# ", "\n## ", "\n### ", "\n#### ", "\n\n", "\n", " ", ""]) {
|
|
@@ -8371,8 +8456,11 @@ ${m.content}`).join("\n\n---\n\n");
|
|
|
8371
8456
|
fullSources = fullSources.slice(0, topK);
|
|
8372
8457
|
}
|
|
8373
8458
|
const rerankMs = performance.now() - rerankStart;
|
|
8374
|
-
let context = fullSources.length ? fullSources.map((m, i) =>
|
|
8375
|
-
|
|
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.";
|
|
8376
8464
|
let displayCount = 15;
|
|
8377
8465
|
if (hasMetadataFilter) {
|
|
8378
8466
|
displayCount = fullSources.length;
|
|
@@ -8456,7 +8544,10 @@ ${context}`;
|
|
|
8456
8544
|
if (isSimulatedThinking) {
|
|
8457
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.`)";
|
|
8458
8546
|
}
|
|
8459
|
-
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
|
+
}));
|
|
8460
8551
|
const userQuestion = { role: "user", content: question + finalRestrictionSuffix };
|
|
8461
8552
|
const messages = [...hardenedHistory, userQuestion];
|
|
8462
8553
|
const systemPrompt = (_v = this.config.llm.systemPrompt) != null ? _v : "";
|
|
@@ -8603,13 +8694,13 @@ ${context}`;
|
|
|
8603
8694
|
rewrittenQuery,
|
|
8604
8695
|
systemPrompt,
|
|
8605
8696
|
userPrompt: question + finalRestrictionSuffix,
|
|
8606
|
-
chunks: sources.map((s) => {
|
|
8607
|
-
var _a3;
|
|
8697
|
+
chunks: (sources || []).filter(Boolean).map((s) => {
|
|
8698
|
+
var _a3, _b2;
|
|
8608
8699
|
return {
|
|
8609
8700
|
id: s.id,
|
|
8610
8701
|
score: s.score,
|
|
8611
|
-
content: s.content,
|
|
8612
|
-
metadata: (
|
|
8702
|
+
content: (_a3 = s == null ? void 0 : s.content) != null ? _a3 : "",
|
|
8703
|
+
metadata: (_b2 = s == null ? void 0 : s.metadata) != null ? _b2 : {},
|
|
8613
8704
|
namespace: ns
|
|
8614
8705
|
};
|
|
8615
8706
|
}),
|
|
@@ -9510,6 +9601,7 @@ import { NextResponse } from "next/server";
|
|
|
9510
9601
|
// src/core/DatabaseStorage.ts
|
|
9511
9602
|
import * as fs from "fs";
|
|
9512
9603
|
import * as path from "path";
|
|
9604
|
+
import * as os from "os";
|
|
9513
9605
|
var DatabaseStorage = class {
|
|
9514
9606
|
constructor(config) {
|
|
9515
9607
|
// Dynamic PG Pool
|
|
@@ -9518,7 +9610,8 @@ var DatabaseStorage = class {
|
|
|
9518
9610
|
this.mongoClient = null;
|
|
9519
9611
|
this.mongoDbName = "";
|
|
9520
9612
|
// Filesystem fallback configuration
|
|
9521
|
-
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");
|
|
9522
9615
|
this.historyFile = path.join(this.fallbackDir, "history.json");
|
|
9523
9616
|
this.feedbackFile = path.join(this.fallbackDir, "feedback.json");
|
|
9524
9617
|
var _a2, _b, _c, _d, _e;
|
|
@@ -9648,10 +9741,27 @@ var DatabaseStorage = class {
|
|
|
9648
9741
|
}
|
|
9649
9742
|
// Helper for FS fallback writes
|
|
9650
9743
|
writeLocalFile(filePath, data) {
|
|
9651
|
-
|
|
9652
|
-
|
|
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
|
+
}
|
|
9653
9764
|
}
|
|
9654
|
-
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
9655
9765
|
}
|
|
9656
9766
|
// ─── Message History Operations ──────────────────────────────────────────
|
|
9657
9767
|
async saveMessage(sessionId, message) {
|
|
@@ -10083,7 +10193,17 @@ function createChatHandler(configOrPlugin, options) {
|
|
|
10083
10193
|
if (rateLimited) return rateLimited;
|
|
10084
10194
|
try {
|
|
10085
10195
|
const body = await req.json();
|
|
10086
|
-
const
|
|
10196
|
+
const bodyObj = body != null ? body : {};
|
|
10197
|
+
let rawMessage = bodyObj.message;
|
|
10198
|
+
if (!rawMessage && Array.isArray(bodyObj.messages) && bodyObj.messages.length > 0) {
|
|
10199
|
+
const lastMsg = bodyObj.messages[bodyObj.messages.length - 1];
|
|
10200
|
+
rawMessage = typeof lastMsg === "string" ? lastMsg : (lastMsg == null ? void 0 : lastMsg.content) || (lastMsg == null ? void 0 : lastMsg.text);
|
|
10201
|
+
}
|
|
10202
|
+
if (!rawMessage && typeof bodyObj.prompt === "string") {
|
|
10203
|
+
rawMessage = bodyObj.prompt;
|
|
10204
|
+
}
|
|
10205
|
+
const history = bodyObj.history || (Array.isArray(bodyObj.messages) ? bodyObj.messages.slice(0, -1) : []);
|
|
10206
|
+
const { namespace, sessionId = "default", messageId, userMessageId } = bodyObj;
|
|
10087
10207
|
const sanitized = sanitizeInput(rawMessage != null ? rawMessage : "");
|
|
10088
10208
|
if (!sanitized.ok) {
|
|
10089
10209
|
return NextResponse.json({ error: { code: "INVALID_INPUT", message: sanitized.error } }, { status: 400 });
|
|
@@ -10135,7 +10255,17 @@ function createStreamHandler(configOrPlugin, options) {
|
|
|
10135
10255
|
headers: { "Content-Type": "application/json" }
|
|
10136
10256
|
});
|
|
10137
10257
|
}
|
|
10138
|
-
const
|
|
10258
|
+
const bodyObj = body != null ? body : {};
|
|
10259
|
+
let rawMessage = bodyObj.message;
|
|
10260
|
+
if (!rawMessage && Array.isArray(bodyObj.messages) && bodyObj.messages.length > 0) {
|
|
10261
|
+
const lastMsg = bodyObj.messages[bodyObj.messages.length - 1];
|
|
10262
|
+
rawMessage = typeof lastMsg === "string" ? lastMsg : (lastMsg == null ? void 0 : lastMsg.content) || (lastMsg == null ? void 0 : lastMsg.text);
|
|
10263
|
+
}
|
|
10264
|
+
if (!rawMessage && typeof bodyObj.prompt === "string") {
|
|
10265
|
+
rawMessage = bodyObj.prompt;
|
|
10266
|
+
}
|
|
10267
|
+
const history = bodyObj.history || (Array.isArray(bodyObj.messages) ? bodyObj.messages.slice(0, -1) : []);
|
|
10268
|
+
const { namespace, sessionId = "default", messageId, userMessageId } = bodyObj;
|
|
10139
10269
|
const sanitized = sanitizeInput(rawMessage != null ? rawMessage : "");
|
|
10140
10270
|
if (!sanitized.ok) {
|
|
10141
10271
|
return new Response(
|