@retrivora-ai/rag-engine 1.9.2 → 1.9.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/README.md +27 -0
- package/dist/{ILLMProvider-Bw2A28nU.d.mts → ILLMProvider-DNhyOYoK.d.mts} +41 -1
- package/dist/{ILLMProvider-Bw2A28nU.d.ts → ILLMProvider-DNhyOYoK.d.ts} +41 -1
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +563 -205
- package/dist/handlers/index.mjs +563 -205
- package/dist/index-C9v7-tWd.d.mts +183 -0
- package/dist/{index-B70ZLkfG.d.mts → index-CHL1jdYm.d.mts} +1 -1
- package/dist/index-CjQdL0cX.d.ts +183 -0
- package/dist/{index-DVu-mkAM.d.ts → index-Hgbwl9X4.d.ts} +1 -1
- package/dist/index.css +40 -0
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +326 -158
- package/dist/index.mjs +312 -151
- package/dist/server.d.mts +15 -94
- package/dist/server.d.ts +15 -94
- package/dist/server.js +623 -205
- package/dist/server.mjs +615 -205
- package/package.json +1 -1
- package/src/app/api/chat/route.ts +2 -2
- package/src/app/api/health/route.ts +3 -2
- package/src/app/api/ingest/route.ts +3 -2
- package/src/app/api/suggestions/route.ts +3 -2
- package/src/app/api/upload/route.ts +3 -2
- package/src/app/constants.tsx +85 -30
- package/src/app/layout.tsx +18 -7
- package/src/components/MessageBubble.tsx +39 -2
- package/src/components/ThinkingBlock.tsx +75 -0
- package/src/components/VisualizationRenderer.tsx +27 -1
- package/src/config/RagConfig.ts +47 -0
- package/src/config/serverConfig.ts +25 -0
- package/src/core/ConfigResolver.ts +56 -4
- package/src/core/ConfigValidator.ts +2 -1
- package/src/core/Pipeline.ts +226 -68
- package/src/core/ProviderRegistry.ts +11 -2
- package/src/core/QueryProcessor.ts +38 -4
- package/src/core/Retrivora.ts +51 -0
- package/src/exceptions/index.ts +59 -0
- package/src/handlers/index.ts +2 -0
- package/src/hooks/useRagChat.ts +26 -4
- package/src/index.ts +25 -1
- package/src/lib/plugin.ts +24 -0
- package/src/llm/LLMFactory.ts +4 -1
- package/src/llm/providers/AnthropicProvider.ts +70 -20
- package/src/llm/providers/GeminiProvider.ts +14 -15
- package/src/llm/providers/OllamaProvider.ts +13 -16
- package/src/llm/providers/OpenAIProvider.ts +9 -14
- package/src/llm/providers/UniversalLLMAdapter.ts +5 -5
- package/src/llm/utils.ts +46 -0
- package/src/providers/vectordb/MongoDBProvider.ts +19 -7
- package/src/providers/vectordb/MultiTablePostgresProvider.ts +45 -13
- package/src/rag/EntityExtractor.ts +2 -2
- package/src/rag/Reranker.ts +9 -16
- package/src/server.ts +27 -1
- package/src/types/chat.ts +7 -0
- package/src/utils/UITransformer.ts +73 -4
- package/dist/DocumentChunker-Dh9TvmGG.d.mts +0 -45
- package/dist/DocumentChunker-Dh9TvmGG.d.ts +0 -45
package/dist/server.js
CHANGED
|
@@ -661,6 +661,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
661
661
|
CREATE INDEX IF NOT EXISTS ${this.uploadTable}_embedding_idx
|
|
662
662
|
ON ${this.uploadTable}
|
|
663
663
|
USING hnsw (embedding vector_cosine_ops)
|
|
664
|
+
`);
|
|
665
|
+
await client.query(`
|
|
666
|
+
CREATE INDEX IF NOT EXISTS "${this.uploadTable}_fts_idx"
|
|
667
|
+
ON "${this.uploadTable}"
|
|
668
|
+
USING gin (to_tsvector('english', content))
|
|
664
669
|
`);
|
|
665
670
|
const res = await client.query(`
|
|
666
671
|
SELECT table_name
|
|
@@ -731,6 +736,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
731
736
|
CREATE INDEX IF NOT EXISTS "${tableName}_embedding_idx"
|
|
732
737
|
ON "${tableName}"
|
|
733
738
|
USING hnsw (embedding vector_cosine_ops)
|
|
739
|
+
`);
|
|
740
|
+
await client.query(`
|
|
741
|
+
CREATE INDEX IF NOT EXISTS "${tableName}_fts_idx"
|
|
742
|
+
ON "${tableName}"
|
|
743
|
+
USING gin (to_tsvector('english', content))
|
|
734
744
|
`);
|
|
735
745
|
if (!this.tables.includes(tableName)) {
|
|
736
746
|
this.tables.push(tableName);
|
|
@@ -822,8 +832,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
822
832
|
const paramIdx = baseOffset + filterParams.length;
|
|
823
833
|
const synonyms = (_a3 = FIELD_SYNONYMS[key]) != null ? _a3 : [];
|
|
824
834
|
const keysToCheck = [key, ...synonyms];
|
|
825
|
-
const coalesceExprs = keysToCheck.
|
|
826
|
-
|
|
835
|
+
const coalesceExprs = keysToCheck.flatMap((k) => [
|
|
836
|
+
`metadata->>'${k}'`,
|
|
837
|
+
`to_jsonb(t)->>'${k}'`
|
|
838
|
+
]);
|
|
839
|
+
return `COALESCE(${coalesceExprs.map((expr) => `LOWER(${expr})`).join(", ")}) = LOWER($${paramIdx})`;
|
|
827
840
|
});
|
|
828
841
|
whereClause = `WHERE ${conditions.join(" AND ")}`;
|
|
829
842
|
}
|
|
@@ -834,16 +847,35 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
834
847
|
CASE WHEN LOWER(val) IN (${entityHints.map((h) => `'${h.replace(/'/g, "''")}'`).join(", ")})
|
|
835
848
|
THEN 1.0 ELSE 0.0 END
|
|
836
849
|
), 0)
|
|
837
|
-
FROM jsonb_each_text(
|
|
850
|
+
FROM jsonb_each_text(COALESCE(v.metadata, k.metadata)) AS kv(key, val)
|
|
838
851
|
WHERE key IN (${this.searchFields.map((f) => `'${f}'`).join(", ")})
|
|
839
852
|
) * 3.0` : "";
|
|
840
853
|
sqlQuery = `
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
854
|
+
WITH vector_search AS (
|
|
855
|
+
SELECT *, (1 - (embedding <=> $1::vector)) AS vector_score
|
|
856
|
+
FROM "${table}" t
|
|
857
|
+
${whereClause}
|
|
858
|
+
ORDER BY embedding <=> $1::vector ASC
|
|
859
|
+
LIMIT ${tableLimit}
|
|
860
|
+
),
|
|
861
|
+
keyword_search AS (
|
|
862
|
+
SELECT *, COALESCE(ts_rank(to_tsvector('english', content), to_tsquery('english', $2)), 0) AS keyword_score
|
|
863
|
+
FROM "${table}" t
|
|
864
|
+
WHERE ${whereClause ? whereClause.replace("WHERE", "") : "TRUE"}
|
|
865
|
+
AND to_tsvector('english', content) @@ to_tsquery('english', $2)
|
|
866
|
+
ORDER BY keyword_score DESC
|
|
867
|
+
LIMIT ${tableLimit}
|
|
868
|
+
)
|
|
869
|
+
SELECT
|
|
870
|
+
COALESCE(v.id, k.id) AS id,
|
|
871
|
+
COALESCE(v.namespace, k.namespace) AS namespace,
|
|
872
|
+
COALESCE(v.content, k.content) AS content,
|
|
873
|
+
COALESCE(v.metadata, k.metadata) AS metadata,
|
|
874
|
+
COALESCE(v.vector_score, 0) AS vector_score,
|
|
875
|
+
COALESCE(k.keyword_score, 0) AS keyword_score,
|
|
876
|
+
(COALESCE(v.vector_score, 0) + COALESCE(k.keyword_score, 0) * 2.0 ${exactNameScoreExpr}) AS hybrid_score
|
|
877
|
+
FROM vector_search v
|
|
878
|
+
FULL OUTER JOIN keyword_search k ON v.id = k.id
|
|
847
879
|
ORDER BY hybrid_score DESC
|
|
848
880
|
LIMIT ${tableLimit}
|
|
849
881
|
`;
|
|
@@ -854,7 +886,7 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
854
886
|
(1 - (embedding <=> $1::vector)) AS hybrid_score
|
|
855
887
|
FROM "${table}" t
|
|
856
888
|
${whereClause}
|
|
857
|
-
ORDER BY
|
|
889
|
+
ORDER BY embedding <=> $1::vector ASC
|
|
858
890
|
LIMIT ${tableLimit}
|
|
859
891
|
`;
|
|
860
892
|
params = [vectorLiteral, ...filterParams];
|
|
@@ -1060,7 +1092,11 @@ var init_MongoDBProvider = __esm({
|
|
|
1060
1092
|
if (key === "namespace") {
|
|
1061
1093
|
vectorSearchFilter.namespace = value;
|
|
1062
1094
|
} else {
|
|
1063
|
-
|
|
1095
|
+
if (typeof value === "string") {
|
|
1096
|
+
matchFilter[key] = { $regex: new RegExp(`^${value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "i") };
|
|
1097
|
+
} else {
|
|
1098
|
+
matchFilter[key] = value;
|
|
1099
|
+
}
|
|
1064
1100
|
}
|
|
1065
1101
|
}
|
|
1066
1102
|
const pipeline = [
|
|
@@ -1090,12 +1126,15 @@ var init_MongoDBProvider = __esm({
|
|
|
1090
1126
|
}
|
|
1091
1127
|
);
|
|
1092
1128
|
const results = await this.collection.aggregate(pipeline).toArray();
|
|
1093
|
-
return results.map((res) =>
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1129
|
+
return results.map((res) => {
|
|
1130
|
+
const normalizedScore = res.score * 2 - 1;
|
|
1131
|
+
return {
|
|
1132
|
+
id: res._id,
|
|
1133
|
+
content: res[this.contentKey],
|
|
1134
|
+
metadata: res[this.metadataKey] || {},
|
|
1135
|
+
score: normalizedScore
|
|
1136
|
+
};
|
|
1137
|
+
});
|
|
1099
1138
|
}
|
|
1100
1139
|
async delete(id, namespace) {
|
|
1101
1140
|
await this.collection.deleteOne(__spreadValues({ _id: id }, namespace ? { namespace } : {}));
|
|
@@ -2063,14 +2102,17 @@ var init_SimpleGraphProvider = __esm({
|
|
|
2063
2102
|
var server_exports = {};
|
|
2064
2103
|
__export(server_exports, {
|
|
2065
2104
|
AnthropicProvider: () => AnthropicProvider,
|
|
2105
|
+
AuthenticationException: () => AuthenticationException,
|
|
2066
2106
|
BaseVectorProvider: () => BaseVectorProvider,
|
|
2067
2107
|
BatchProcessor: () => BatchProcessor,
|
|
2068
2108
|
ChromaDBProvider: () => ChromaDBProvider,
|
|
2069
2109
|
ConfigBuilder: () => ConfigBuilder,
|
|
2070
2110
|
ConfigResolver: () => ConfigResolver,
|
|
2071
2111
|
ConfigValidator: () => ConfigValidator,
|
|
2112
|
+
ConfigurationException: () => ConfigurationException,
|
|
2072
2113
|
DocumentChunker: () => DocumentChunker,
|
|
2073
2114
|
DocumentParser: () => DocumentParser,
|
|
2115
|
+
EmbeddingFailedException: () => EmbeddingFailedException,
|
|
2074
2116
|
EmbeddingStrategy: () => EmbeddingStrategy,
|
|
2075
2117
|
EmbeddingStrategyResolver: () => EmbeddingStrategyResolver,
|
|
2076
2118
|
LLMFactory: () => LLMFactory,
|
|
@@ -2085,9 +2127,14 @@ __export(server_exports, {
|
|
|
2085
2127
|
Pipeline: () => Pipeline,
|
|
2086
2128
|
PostgreSQLProvider: () => PostgreSQLProvider,
|
|
2087
2129
|
ProviderHealthCheck: () => ProviderHealthCheck,
|
|
2130
|
+
ProviderNotFoundException: () => ProviderNotFoundException,
|
|
2088
2131
|
ProviderRegistry: () => ProviderRegistry,
|
|
2089
2132
|
QdrantProvider: () => QdrantProvider,
|
|
2133
|
+
RateLimitException: () => RateLimitException,
|
|
2090
2134
|
RedisProvider: () => RedisProvider,
|
|
2135
|
+
RetrievalException: () => RetrievalException,
|
|
2136
|
+
Retrivora: () => Retrivora,
|
|
2137
|
+
RetrivoraError: () => RetrivoraError,
|
|
2091
2138
|
UniversalLLMAdapter: () => UniversalLLMAdapter,
|
|
2092
2139
|
UniversalVectorProvider: () => UniversalVectorProvider,
|
|
2093
2140
|
VECTOR_PROFILES: () => VECTOR_PROFILES,
|
|
@@ -2178,7 +2225,7 @@ function getRagConfig(baseConfig, env = process.env) {
|
|
|
2178
2225
|
return getEnvConfig(env, baseConfig);
|
|
2179
2226
|
}
|
|
2180
2227
|
function getEnvConfig(env = process.env, base) {
|
|
2181
|
-
var _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, _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;
|
|
2228
|
+
var _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, _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;
|
|
2182
2229
|
const projectId = (_c = (_b = (_a = readString(env, "RAG_PROJECT_ID")) != null ? _a : readString(env, "NEXT_PUBLIC_PROJECT_ID")) != null ? _b : base == null ? void 0 : base.projectId) != null ? _c : "__default__";
|
|
2183
2230
|
const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
|
|
2184
2231
|
const llmProvider = readEnum(env, "LLM_PROVIDER", "openai", LLM_PROVIDERS);
|
|
@@ -2248,7 +2295,7 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2248
2295
|
rest: "default",
|
|
2249
2296
|
custom: "default"
|
|
2250
2297
|
};
|
|
2251
|
-
return {
|
|
2298
|
+
return __spreadValues({
|
|
2252
2299
|
projectId,
|
|
2253
2300
|
vectorDb: {
|
|
2254
2301
|
provider: vectorProvider,
|
|
@@ -2264,7 +2311,9 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2264
2311
|
maxTokens: readNumber(env, "LLM_MAX_TOKENS", 4096),
|
|
2265
2312
|
temperature: readNumber(env, "LLM_TEMPERATURE", 0.7),
|
|
2266
2313
|
options: {
|
|
2267
|
-
profile: readString(env, "LLM_UNIVERSAL_PROFILE")
|
|
2314
|
+
profile: readString(env, "LLM_UNIVERSAL_PROFILE"),
|
|
2315
|
+
thinking: readString(env, "LLM_THINKING") === "true" || readString(env, "LLM_THINKING") === "enabled" ? true : readString(env, "LLM_THINKING") === "false" ? false : void 0,
|
|
2316
|
+
thinkingBudget: env.LLM_THINKING_BUDGET ? parseInt(env.LLM_THINKING_BUDGET, 10) : void 0
|
|
2268
2317
|
}
|
|
2269
2318
|
},
|
|
2270
2319
|
embedding: {
|
|
@@ -2296,11 +2345,76 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2296
2345
|
topK: readNumber(env, "RAG_TOP_K", 5),
|
|
2297
2346
|
scoreThreshold: readNumber(env, "RAG_SCORE_THRESHOLD", 0),
|
|
2298
2347
|
chunkSize: readNumber(env, "RAG_CHUNK_SIZE", 1e3),
|
|
2299
|
-
chunkOverlap: readNumber(env, "RAG_CHUNK_OVERLAP", 200)
|
|
2348
|
+
chunkOverlap: readNumber(env, "RAG_CHUNK_OVERLAP", 200),
|
|
2349
|
+
filterableFields: (_Ha = readString(env, "RAG_FILTERABLE_FIELDS")) == null ? void 0 : _Ha.split(",").map((f) => f.trim()),
|
|
2350
|
+
// Query pipeline toggles — read from .env.local
|
|
2351
|
+
useQueryTransformation: readString(env, "RAG_USE_QUERY_TRANSFORMATION") === "true",
|
|
2352
|
+
useReranking: readString(env, "RAG_USE_RERANKING") === "true",
|
|
2353
|
+
useGraphRetrieval: readString(env, "RAG_USE_GRAPH_RETRIEVAL") === "true",
|
|
2354
|
+
architecture: (_Ia = readString(env, "RAG_ARCHITECTURE")) != null ? _Ia : "simple",
|
|
2355
|
+
chunkingStrategy: (_Ja = readString(env, "RAG_CHUNKING_STRATEGY")) != null ? _Ja : "recursive",
|
|
2356
|
+
uiMapping: (() => {
|
|
2357
|
+
const raw = readString(env, "RAG_UI_MAPPING");
|
|
2358
|
+
if (!raw) return void 0;
|
|
2359
|
+
try {
|
|
2360
|
+
return JSON.parse(raw);
|
|
2361
|
+
} catch (e) {
|
|
2362
|
+
return void 0;
|
|
2363
|
+
}
|
|
2364
|
+
})()
|
|
2300
2365
|
}
|
|
2301
|
-
}
|
|
2366
|
+
}, readString(env, "GRAPH_DB_PROVIDER") ? {
|
|
2367
|
+
graphDb: {
|
|
2368
|
+
provider: readString(env, "GRAPH_DB_PROVIDER"),
|
|
2369
|
+
options: {
|
|
2370
|
+
uri: readString(env, "GRAPH_DB_URI"),
|
|
2371
|
+
username: readString(env, "GRAPH_DB_USERNAME"),
|
|
2372
|
+
password: readString(env, "GRAPH_DB_PASSWORD")
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
} : {});
|
|
2302
2376
|
}
|
|
2303
2377
|
|
|
2378
|
+
// src/exceptions/index.ts
|
|
2379
|
+
var RetrivoraError = class extends Error {
|
|
2380
|
+
constructor(message, code, details) {
|
|
2381
|
+
super(message);
|
|
2382
|
+
this.name = new.target.name;
|
|
2383
|
+
this.code = code;
|
|
2384
|
+
this.details = details;
|
|
2385
|
+
}
|
|
2386
|
+
};
|
|
2387
|
+
var ProviderNotFoundException = class extends RetrivoraError {
|
|
2388
|
+
constructor(providerType, provider, details) {
|
|
2389
|
+
super(`Unsupported ${providerType} provider: ${provider}`, "PROVIDER_NOT_FOUND", details);
|
|
2390
|
+
}
|
|
2391
|
+
};
|
|
2392
|
+
var EmbeddingFailedException = class extends RetrivoraError {
|
|
2393
|
+
constructor(message = "Embedding generation failed", details) {
|
|
2394
|
+
super(message, "EMBEDDING_FAILED", details);
|
|
2395
|
+
}
|
|
2396
|
+
};
|
|
2397
|
+
var RetrievalException = class extends RetrivoraError {
|
|
2398
|
+
constructor(message = "Retrieval failed", details) {
|
|
2399
|
+
super(message, "RETRIEVAL_FAILED", details);
|
|
2400
|
+
}
|
|
2401
|
+
};
|
|
2402
|
+
var RateLimitException = class extends RetrivoraError {
|
|
2403
|
+
constructor(message = "Provider rate limit exceeded", details) {
|
|
2404
|
+
super(message, "RATE_LIMITED", details);
|
|
2405
|
+
}
|
|
2406
|
+
};
|
|
2407
|
+
var ConfigurationException = class extends RetrivoraError {
|
|
2408
|
+
constructor(message, details) {
|
|
2409
|
+
super(message, "CONFIGURATION_ERROR", details);
|
|
2410
|
+
}
|
|
2411
|
+
};
|
|
2412
|
+
var AuthenticationException = class extends RetrivoraError {
|
|
2413
|
+
constructor(message = "Provider authentication failed", details) {
|
|
2414
|
+
super(message, "AUTHENTICATION_ERROR", details);
|
|
2415
|
+
}
|
|
2416
|
+
};
|
|
2417
|
+
|
|
2304
2418
|
// src/core/ConfigResolver.ts
|
|
2305
2419
|
var ConfigResolver = class {
|
|
2306
2420
|
/**
|
|
@@ -2327,24 +2441,81 @@ var ConfigResolver = class {
|
|
|
2327
2441
|
rag: hostConfig.rag ? __spreadValues(__spreadValues({}, envConfig.rag), hostConfig.rag) : envConfig.rag
|
|
2328
2442
|
});
|
|
2329
2443
|
}
|
|
2444
|
+
/**
|
|
2445
|
+
* Resolves the public SDK config shape used by `new Retrivora({...})`.
|
|
2446
|
+
* Supports aliases from the product prompt while preserving existing env
|
|
2447
|
+
* fallback behavior.
|
|
2448
|
+
*/
|
|
2449
|
+
static resolveUniversal(hostConfig, env = process.env) {
|
|
2450
|
+
var _a;
|
|
2451
|
+
if (!hostConfig) return this.resolve(void 0, env);
|
|
2452
|
+
const normalized = __spreadProps(__spreadValues({}, hostConfig), {
|
|
2453
|
+
vectorDb: (_a = hostConfig.vectorDb) != null ? _a : hostConfig.vectorDatabase,
|
|
2454
|
+
rag: this.mergeRetrievalWorkflow(hostConfig.rag, hostConfig.retrieval, hostConfig.workflow)
|
|
2455
|
+
});
|
|
2456
|
+
return this.resolve(normalized, env);
|
|
2457
|
+
}
|
|
2330
2458
|
/**
|
|
2331
2459
|
* Validates the configuration for required fields.
|
|
2332
2460
|
*/
|
|
2333
2461
|
static validate(config) {
|
|
2334
2462
|
if (!config.projectId) {
|
|
2335
|
-
throw new
|
|
2463
|
+
throw new ConfigurationException("[ConfigResolver] projectId is required");
|
|
2336
2464
|
}
|
|
2337
2465
|
if (!config.vectorDb.provider) {
|
|
2338
|
-
throw new
|
|
2466
|
+
throw new ConfigurationException("[ConfigResolver] vectorDb.provider is required");
|
|
2339
2467
|
}
|
|
2340
2468
|
if (!config.llm.provider) {
|
|
2341
|
-
throw new
|
|
2469
|
+
throw new ConfigurationException("[ConfigResolver] llm.provider is required");
|
|
2342
2470
|
}
|
|
2343
2471
|
}
|
|
2472
|
+
static mergeRetrievalWorkflow(rag, retrieval, workflow) {
|
|
2473
|
+
var _a, _b, _c, _d, _e;
|
|
2474
|
+
if (!rag && !retrieval && !workflow) return void 0;
|
|
2475
|
+
const normalized = __spreadValues({}, rag != null ? rag : {});
|
|
2476
|
+
if (retrieval) {
|
|
2477
|
+
normalized.topK = (_a = retrieval.topK) != null ? _a : normalized.topK;
|
|
2478
|
+
normalized.scoreThreshold = (_b = retrieval.scoreThreshold) != null ? _b : normalized.scoreThreshold;
|
|
2479
|
+
normalized.useReranking = (_c = retrieval.useReranking) != null ? _c : normalized.useReranking;
|
|
2480
|
+
if (retrieval.strategy === "hybrid") normalized.architecture = (_d = normalized.architecture) != null ? _d : "hybrid";
|
|
2481
|
+
if (retrieval.strategy === "agentic") normalized.architecture = "agentic";
|
|
2482
|
+
if (retrieval.strategy === "contextual-compression") normalized.useReranking = true;
|
|
2483
|
+
}
|
|
2484
|
+
if (workflow == null ? void 0 : workflow.type) {
|
|
2485
|
+
const type = workflow.type;
|
|
2486
|
+
if (type === "agentic" || type === "agentic-rag") normalized.architecture = "agentic";
|
|
2487
|
+
else if (type === "hybrid-rag") normalized.architecture = "hybrid";
|
|
2488
|
+
else if (type === "graph-rag") {
|
|
2489
|
+
normalized.architecture = "graph";
|
|
2490
|
+
normalized.useGraphRetrieval = true;
|
|
2491
|
+
} else if (type === "simple-rag" || type === "rag") {
|
|
2492
|
+
normalized.architecture = (_e = normalized.architecture) != null ? _e : "simple";
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
return normalized;
|
|
2496
|
+
}
|
|
2344
2497
|
};
|
|
2345
2498
|
|
|
2346
2499
|
// src/llm/providers/OpenAIProvider.ts
|
|
2347
2500
|
var import_openai = __toESM(require("openai"));
|
|
2501
|
+
|
|
2502
|
+
// src/llm/utils.ts
|
|
2503
|
+
function buildSystemContent(systemPrompt, context) {
|
|
2504
|
+
const noContext = !context || context.trim() === "" || context.trim() === "No relevant context found.";
|
|
2505
|
+
if (systemPrompt.includes("{{context}}")) {
|
|
2506
|
+
return systemPrompt.replace("{{context}}", noContext ? "" : context);
|
|
2507
|
+
}
|
|
2508
|
+
if (noContext) {
|
|
2509
|
+
return systemPrompt;
|
|
2510
|
+
}
|
|
2511
|
+
return `${systemPrompt}
|
|
2512
|
+
|
|
2513
|
+
---
|
|
2514
|
+
Context:
|
|
2515
|
+
${context}`;
|
|
2516
|
+
}
|
|
2517
|
+
|
|
2518
|
+
// src/llm/providers/OpenAIProvider.ts
|
|
2348
2519
|
var OpenAIProvider = class {
|
|
2349
2520
|
constructor(llmConfig, embeddingConfig) {
|
|
2350
2521
|
if (!llmConfig.apiKey) throw new Error("[OpenAIProvider] llmConfig.apiKey is required");
|
|
@@ -2408,16 +2579,10 @@ var OpenAIProvider = class {
|
|
|
2408
2579
|
}
|
|
2409
2580
|
async chat(messages, context, options) {
|
|
2410
2581
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
2411
|
-
const
|
|
2412
|
-
|
|
2413
|
-
Context:
|
|
2414
|
-
${context}`;
|
|
2582
|
+
const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
2415
2583
|
const systemMessage = {
|
|
2416
2584
|
role: "system",
|
|
2417
|
-
content:
|
|
2418
|
-
|
|
2419
|
-
Context:
|
|
2420
|
-
${context}`
|
|
2585
|
+
content: buildSystemContent(basePrompt, context)
|
|
2421
2586
|
};
|
|
2422
2587
|
const formattedMessages = [
|
|
2423
2588
|
systemMessage,
|
|
@@ -2438,16 +2603,10 @@ ${context}`
|
|
|
2438
2603
|
chatStream(messages, context, options) {
|
|
2439
2604
|
return __asyncGenerator(this, null, function* () {
|
|
2440
2605
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
2441
|
-
const
|
|
2442
|
-
|
|
2443
|
-
Context:
|
|
2444
|
-
${context}`;
|
|
2606
|
+
const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
2445
2607
|
const systemMessage = {
|
|
2446
2608
|
role: "system",
|
|
2447
|
-
content:
|
|
2448
|
-
|
|
2449
|
-
Context:
|
|
2450
|
-
${context}`
|
|
2609
|
+
content: buildSystemContent(basePrompt, context)
|
|
2451
2610
|
};
|
|
2452
2611
|
const formattedMessages = [
|
|
2453
2612
|
systemMessage,
|
|
@@ -2568,58 +2727,87 @@ var AnthropicProvider = class {
|
|
|
2568
2727
|
};
|
|
2569
2728
|
}
|
|
2570
2729
|
async chat(messages, context, options) {
|
|
2571
|
-
var _a, _b, _c, _d;
|
|
2572
|
-
const
|
|
2573
|
-
|
|
2574
|
-
Context:
|
|
2575
|
-
${context}`;
|
|
2576
|
-
const system = resolvedPrompt.includes("{{context}}") ? resolvedPrompt.replace("{{context}}", context) : (options == null ? void 0 : options.systemPrompt) ? resolvedPrompt : `${resolvedPrompt}
|
|
2577
|
-
|
|
2578
|
-
Context:
|
|
2579
|
-
${context}`;
|
|
2730
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
2731
|
+
const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the context below to answer the user's question accurately.";
|
|
2732
|
+
const system = buildSystemContent(basePrompt, context);
|
|
2580
2733
|
const anthropicMessages = messages.map((m) => ({
|
|
2581
2734
|
role: m.role === "assistant" ? "assistant" : "user",
|
|
2582
2735
|
content: m.content
|
|
2583
2736
|
}));
|
|
2584
|
-
const
|
|
2737
|
+
const isClaude37 = this.llmConfig.model.includes("claude-3-7-sonnet");
|
|
2738
|
+
const isThinkingEnabled = ((_c = this.llmConfig.options) == null ? void 0 : _c.thinking) === true || ((_d = this.llmConfig.options) == null ? void 0 : _d.thinking) === "enabled" || isClaude37 && ((_e = this.llmConfig.options) == null ? void 0 : _e.thinking) !== false;
|
|
2739
|
+
const extraParams = {};
|
|
2740
|
+
if (isThinkingEnabled && isClaude37) {
|
|
2741
|
+
extraParams.betas = ["interleaved-thinking-2025-05-14"];
|
|
2742
|
+
const maxTokens = (_g = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g : 4096;
|
|
2743
|
+
const budget = Math.min(
|
|
2744
|
+
typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
|
|
2745
|
+
maxTokens - 1
|
|
2746
|
+
);
|
|
2747
|
+
extraParams.thinking = {
|
|
2748
|
+
type: "enabled",
|
|
2749
|
+
budget_tokens: budget
|
|
2750
|
+
};
|
|
2751
|
+
extraParams.max_tokens = Math.max(maxTokens, budget + 1024);
|
|
2752
|
+
}
|
|
2753
|
+
const response = await this.client.messages.create(__spreadValues({
|
|
2585
2754
|
model: this.llmConfig.model,
|
|
2586
|
-
max_tokens: (
|
|
2755
|
+
max_tokens: (_k = (_j = options == null ? void 0 : options.maxTokens) != null ? _j : this.llmConfig.maxTokens) != null ? _k : 1024,
|
|
2587
2756
|
system,
|
|
2588
2757
|
messages: anthropicMessages
|
|
2589
|
-
});
|
|
2590
|
-
|
|
2591
|
-
|
|
2758
|
+
}, extraParams));
|
|
2759
|
+
let reply = "";
|
|
2760
|
+
for (const block of response.content) {
|
|
2761
|
+
if (block.type === "text") {
|
|
2762
|
+
reply += block.text;
|
|
2763
|
+
}
|
|
2764
|
+
}
|
|
2765
|
+
return reply;
|
|
2592
2766
|
}
|
|
2593
2767
|
chatStream(messages, context, options) {
|
|
2594
2768
|
return __asyncGenerator(this, null, function* () {
|
|
2595
|
-
var _a, _b, _c, _d;
|
|
2596
|
-
const
|
|
2597
|
-
|
|
2598
|
-
Context:
|
|
2599
|
-
${context}`;
|
|
2600
|
-
const system = resolvedPrompt.includes("{{context}}") ? resolvedPrompt.replace("{{context}}", context) : (options == null ? void 0 : options.systemPrompt) ? resolvedPrompt : `${resolvedPrompt}
|
|
2601
|
-
|
|
2602
|
-
Context:
|
|
2603
|
-
${context}`;
|
|
2769
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
2770
|
+
const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the context below to answer the user's question accurately.";
|
|
2771
|
+
const system = buildSystemContent(basePrompt, context);
|
|
2604
2772
|
const anthropicMessages = messages.map((m) => ({
|
|
2605
2773
|
role: m.role === "assistant" ? "assistant" : "user",
|
|
2606
2774
|
content: m.content
|
|
2607
2775
|
}));
|
|
2608
|
-
const
|
|
2776
|
+
const isClaude37 = this.llmConfig.model.includes("claude-3-7-sonnet");
|
|
2777
|
+
const isThinkingEnabled = ((_c = this.llmConfig.options) == null ? void 0 : _c.thinking) === true || ((_d = this.llmConfig.options) == null ? void 0 : _d.thinking) === "enabled" || isClaude37 && ((_e = this.llmConfig.options) == null ? void 0 : _e.thinking) !== false;
|
|
2778
|
+
const extraParams = {};
|
|
2779
|
+
if (isThinkingEnabled && isClaude37) {
|
|
2780
|
+
extraParams.betas = ["interleaved-thinking-2025-05-14"];
|
|
2781
|
+
const maxTokens = (_g = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g : 4096;
|
|
2782
|
+
const budget = Math.min(
|
|
2783
|
+
typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
|
|
2784
|
+
maxTokens - 1
|
|
2785
|
+
);
|
|
2786
|
+
extraParams.thinking = {
|
|
2787
|
+
type: "enabled",
|
|
2788
|
+
budget_tokens: budget
|
|
2789
|
+
};
|
|
2790
|
+
extraParams.max_tokens = Math.max(maxTokens, budget + 1024);
|
|
2791
|
+
}
|
|
2792
|
+
const stream = yield new __await(this.client.messages.create(__spreadValues({
|
|
2609
2793
|
model: this.llmConfig.model,
|
|
2610
|
-
max_tokens: (
|
|
2794
|
+
max_tokens: (_k = (_j = options == null ? void 0 : options.maxTokens) != null ? _j : this.llmConfig.maxTokens) != null ? _k : 1024,
|
|
2611
2795
|
system,
|
|
2612
2796
|
messages: anthropicMessages,
|
|
2613
2797
|
stream: true
|
|
2614
|
-
}));
|
|
2798
|
+
}, extraParams)));
|
|
2615
2799
|
if (!stream) {
|
|
2616
2800
|
throw new Error("[AnthropicProvider] messages.create stream is undefined");
|
|
2617
2801
|
}
|
|
2618
2802
|
try {
|
|
2619
2803
|
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
2620
2804
|
const chunk = temp.value;
|
|
2621
|
-
if (chunk.type === "content_block_delta"
|
|
2622
|
-
|
|
2805
|
+
if (chunk.type === "content_block_delta") {
|
|
2806
|
+
if (chunk.delta.type === "text_delta") {
|
|
2807
|
+
yield chunk.delta.text;
|
|
2808
|
+
} else if (chunk.delta.type === "thinking_delta") {
|
|
2809
|
+
yield `\0THINKING\0${chunk.delta.thinking}`;
|
|
2810
|
+
}
|
|
2623
2811
|
}
|
|
2624
2812
|
}
|
|
2625
2813
|
} catch (temp) {
|
|
@@ -2663,9 +2851,10 @@ ${context}`;
|
|
|
2663
2851
|
var import_axios = __toESM(require("axios"));
|
|
2664
2852
|
var OllamaProvider = class {
|
|
2665
2853
|
constructor(llmConfig, embeddingConfig) {
|
|
2666
|
-
var _a;
|
|
2854
|
+
var _a, _b;
|
|
2667
2855
|
const baseURL = (_a = llmConfig.baseUrl) != null ? _a : "http://localhost:11434";
|
|
2668
|
-
|
|
2856
|
+
const timeout = Number((_b = llmConfig.options) == null ? void 0 : _b.timeout) || 3e5;
|
|
2857
|
+
this.http = import_axios.default.create({ baseURL, timeout });
|
|
2669
2858
|
this.llmConfig = llmConfig;
|
|
2670
2859
|
this.embeddingConfig = embeddingConfig;
|
|
2671
2860
|
}
|
|
@@ -2721,14 +2910,15 @@ var OllamaProvider = class {
|
|
|
2721
2910
|
};
|
|
2722
2911
|
}
|
|
2723
2912
|
async chat(messages, context, options) {
|
|
2724
|
-
var _a, _b, _c, _d;
|
|
2725
|
-
const
|
|
2913
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2914
|
+
const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the provided context to answer the user's question.";
|
|
2915
|
+
const system = buildSystemContent(basePrompt, context);
|
|
2726
2916
|
const { data } = await this.http.post("/api/chat", {
|
|
2727
2917
|
model: this.llmConfig.model,
|
|
2728
2918
|
stream: false,
|
|
2729
2919
|
options: {
|
|
2730
|
-
temperature: (
|
|
2731
|
-
num_predict: (
|
|
2920
|
+
temperature: (_d = (_c = options == null ? void 0 : options.temperature) != null ? _c : this.llmConfig.temperature) != null ? _d : 0.7,
|
|
2921
|
+
num_predict: (_f = (_e = options == null ? void 0 : options.maxTokens) != null ? _e : this.llmConfig.maxTokens) != null ? _f : 1024
|
|
2732
2922
|
},
|
|
2733
2923
|
messages: [
|
|
2734
2924
|
{ role: "system", content: system },
|
|
@@ -2739,14 +2929,15 @@ var OllamaProvider = class {
|
|
|
2739
2929
|
}
|
|
2740
2930
|
chatStream(messages, context, options) {
|
|
2741
2931
|
return __asyncGenerator(this, null, function* () {
|
|
2742
|
-
var _a, _b, _c, _d, _e, _f;
|
|
2743
|
-
const
|
|
2932
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
2933
|
+
const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the provided context to answer the user's question.";
|
|
2934
|
+
const system = buildSystemContent(basePrompt, context);
|
|
2744
2935
|
const response = yield new __await(this.http.post("/api/chat", {
|
|
2745
2936
|
model: this.llmConfig.model,
|
|
2746
2937
|
stream: true,
|
|
2747
2938
|
options: {
|
|
2748
|
-
temperature: (
|
|
2749
|
-
num_predict: (
|
|
2939
|
+
temperature: (_d = (_c = options == null ? void 0 : options.temperature) != null ? _c : this.llmConfig.temperature) != null ? _d : 0.7,
|
|
2940
|
+
num_predict: (_f = (_e = options == null ? void 0 : options.maxTokens) != null ? _e : this.llmConfig.maxTokens) != null ? _f : 1024
|
|
2750
2941
|
},
|
|
2751
2942
|
messages: [
|
|
2752
2943
|
{ role: "system", content: system },
|
|
@@ -2768,7 +2959,7 @@ var OllamaProvider = class {
|
|
|
2768
2959
|
if (!line.trim()) continue;
|
|
2769
2960
|
try {
|
|
2770
2961
|
const json = JSON.parse(line);
|
|
2771
|
-
if ((
|
|
2962
|
+
if ((_g = json.message) == null ? void 0 : _g.content) {
|
|
2772
2963
|
yield json.message.content;
|
|
2773
2964
|
}
|
|
2774
2965
|
if (json.done) return;
|
|
@@ -2790,26 +2981,12 @@ var OllamaProvider = class {
|
|
|
2790
2981
|
if (lineBuffer.trim()) {
|
|
2791
2982
|
try {
|
|
2792
2983
|
const json = JSON.parse(lineBuffer);
|
|
2793
|
-
if ((
|
|
2984
|
+
if ((_h = json.message) == null ? void 0 : _h.content) yield json.message.content;
|
|
2794
2985
|
} catch (e) {
|
|
2795
2986
|
}
|
|
2796
2987
|
}
|
|
2797
2988
|
});
|
|
2798
2989
|
}
|
|
2799
|
-
buildSystemPrompt(context, overridePrompt) {
|
|
2800
|
-
var _a;
|
|
2801
|
-
if (overridePrompt) {
|
|
2802
|
-
return overridePrompt;
|
|
2803
|
-
}
|
|
2804
|
-
const systemPrompt = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Use the provided context to answer the user's question.
|
|
2805
|
-
|
|
2806
|
-
Context:
|
|
2807
|
-
${context}`;
|
|
2808
|
-
return systemPrompt.includes("{{context}}") ? systemPrompt.replace("{{context}}", context) : `${systemPrompt}
|
|
2809
|
-
|
|
2810
|
-
Context:
|
|
2811
|
-
${context}`;
|
|
2812
|
-
}
|
|
2813
2990
|
async embed(text, options) {
|
|
2814
2991
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
2815
2992
|
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "nomic-embed-text";
|
|
@@ -2956,21 +3133,6 @@ var GeminiProvider = class {
|
|
|
2956
3133
|
var _a, _b;
|
|
2957
3134
|
return sanitizeModel((_b = optionsModel != null ? optionsModel : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _b : DEFAULT_EMBEDDING_MODEL);
|
|
2958
3135
|
}
|
|
2959
|
-
/**
|
|
2960
|
-
* Build the system instruction string, inserting the RAG context either via
|
|
2961
|
-
* the `{{context}}` placeholder or by appending it.
|
|
2962
|
-
*/
|
|
2963
|
-
buildSystemInstruction(context) {
|
|
2964
|
-
var _a;
|
|
2965
|
-
const base = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Answer questions based on the provided context.
|
|
2966
|
-
|
|
2967
|
-
Context:
|
|
2968
|
-
${context}`;
|
|
2969
|
-
return base.includes("{{context}}") ? base.replace("{{context}}", context) : `${base}
|
|
2970
|
-
|
|
2971
|
-
Context:
|
|
2972
|
-
${context}`;
|
|
2973
|
-
}
|
|
2974
3136
|
/**
|
|
2975
3137
|
* Convert ChatMessage[] to the Gemini contents format.
|
|
2976
3138
|
*
|
|
@@ -2989,16 +3151,17 @@ ${context}`;
|
|
|
2989
3151
|
// ILLMProvider — chat
|
|
2990
3152
|
// -------------------------------------------------------------------------
|
|
2991
3153
|
async chat(messages, context, options) {
|
|
2992
|
-
var _a, _b, _c, _d;
|
|
3154
|
+
var _a, _b, _c, _d, _e, _f;
|
|
3155
|
+
const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
2993
3156
|
const model = this.client.getGenerativeModel({
|
|
2994
3157
|
model: this.llmConfig.model,
|
|
2995
|
-
systemInstruction:
|
|
3158
|
+
systemInstruction: buildSystemContent(basePrompt, context)
|
|
2996
3159
|
});
|
|
2997
3160
|
const result = await model.generateContent({
|
|
2998
3161
|
contents: this.buildGeminiContents(messages),
|
|
2999
3162
|
generationConfig: {
|
|
3000
|
-
temperature: (
|
|
3001
|
-
maxOutputTokens: (
|
|
3163
|
+
temperature: (_d = (_c = options == null ? void 0 : options.temperature) != null ? _c : this.llmConfig.temperature) != null ? _d : DEFAULT_TEMPERATURE,
|
|
3164
|
+
maxOutputTokens: (_f = (_e = options == null ? void 0 : options.maxTokens) != null ? _e : this.llmConfig.maxTokens) != null ? _f : DEFAULT_MAX_TOKENS,
|
|
3002
3165
|
stopSequences: options == null ? void 0 : options.stop
|
|
3003
3166
|
}
|
|
3004
3167
|
});
|
|
@@ -3006,16 +3169,17 @@ ${context}`;
|
|
|
3006
3169
|
}
|
|
3007
3170
|
chatStream(messages, context, options) {
|
|
3008
3171
|
return __asyncGenerator(this, null, function* () {
|
|
3009
|
-
var _a, _b, _c, _d;
|
|
3172
|
+
var _a, _b, _c, _d, _e, _f;
|
|
3173
|
+
const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
3010
3174
|
const model = this.client.getGenerativeModel({
|
|
3011
3175
|
model: this.llmConfig.model,
|
|
3012
|
-
systemInstruction:
|
|
3176
|
+
systemInstruction: buildSystemContent(basePrompt, context)
|
|
3013
3177
|
});
|
|
3014
3178
|
const result = yield new __await(model.generateContentStream({
|
|
3015
3179
|
contents: this.buildGeminiContents(messages),
|
|
3016
3180
|
generationConfig: {
|
|
3017
|
-
temperature: (
|
|
3018
|
-
maxOutputTokens: (
|
|
3181
|
+
temperature: (_d = (_c = options == null ? void 0 : options.temperature) != null ? _c : this.llmConfig.temperature) != null ? _d : DEFAULT_TEMPERATURE,
|
|
3182
|
+
maxOutputTokens: (_f = (_e = options == null ? void 0 : options.maxTokens) != null ? _e : this.llmConfig.maxTokens) != null ? _f : DEFAULT_MAX_TOKENS,
|
|
3019
3183
|
stopSequences: options == null ? void 0 : options.stop
|
|
3020
3184
|
}
|
|
3021
3185
|
}));
|
|
@@ -3450,7 +3614,9 @@ var LLMFactory = class _LLMFactory {
|
|
|
3450
3614
|
if (llmConfig.baseUrl || ((_b = llmConfig.options) == null ? void 0 : _b.baseUrl)) {
|
|
3451
3615
|
return new UniversalLLMAdapter(llmConfig);
|
|
3452
3616
|
}
|
|
3453
|
-
throw new
|
|
3617
|
+
throw new ProviderNotFoundException(
|
|
3618
|
+
"LLM",
|
|
3619
|
+
String(llmConfig.provider),
|
|
3454
3620
|
`[LLMFactory] Unknown provider "${llmConfig.provider}". Built-in providers: ${_LLMFactory.listProviders().join(", ")}. Register a custom provider with LLMFactory.register().`
|
|
3455
3621
|
);
|
|
3456
3622
|
}
|
|
@@ -3582,7 +3748,7 @@ var ProviderRegistry = class {
|
|
|
3582
3748
|
return UniversalVectorProvider2;
|
|
3583
3749
|
}
|
|
3584
3750
|
default:
|
|
3585
|
-
throw new
|
|
3751
|
+
throw new ProviderNotFoundException("vector", provider);
|
|
3586
3752
|
}
|
|
3587
3753
|
}
|
|
3588
3754
|
static async createVectorProvider(config) {
|
|
@@ -3600,12 +3766,18 @@ var ProviderRegistry = class {
|
|
|
3600
3766
|
return new SimpleGraphProvider2(config);
|
|
3601
3767
|
}
|
|
3602
3768
|
default:
|
|
3603
|
-
throw new
|
|
3769
|
+
throw new ProviderNotFoundException("graph", provider);
|
|
3604
3770
|
}
|
|
3605
3771
|
}
|
|
3606
3772
|
static createLLMProvider(llmConfig, embeddingConfig) {
|
|
3607
3773
|
return LLMFactory.create(llmConfig, embeddingConfig);
|
|
3608
3774
|
}
|
|
3775
|
+
static registerLLMProvider(name, factory) {
|
|
3776
|
+
LLMFactory.register(name, factory);
|
|
3777
|
+
}
|
|
3778
|
+
static createEmbeddingProvider(embeddingConfig) {
|
|
3779
|
+
return LLMFactory.createEmbeddingProvider(embeddingConfig);
|
|
3780
|
+
}
|
|
3609
3781
|
};
|
|
3610
3782
|
ProviderRegistry.vectorProviders = {};
|
|
3611
3783
|
ProviderRegistry.graphProviders = {};
|
|
@@ -3752,8 +3924,8 @@ var ConfigValidator = class {
|
|
|
3752
3924
|
const errorItems = errors.filter((e) => e.severity === "error");
|
|
3753
3925
|
if (errorItems.length > 0) {
|
|
3754
3926
|
const message = errorItems.map((e) => `${e.field}: ${e.message}${e.suggestion ? ` (${e.suggestion})` : ""}`).join("\n ");
|
|
3755
|
-
throw new
|
|
3756
|
-
${message}
|
|
3927
|
+
throw new ConfigurationException(`[ConfigValidator] Configuration validation failed:
|
|
3928
|
+
${message}`, errorItems);
|
|
3757
3929
|
}
|
|
3758
3930
|
}
|
|
3759
3931
|
};
|
|
@@ -3940,20 +4112,17 @@ var Reranker = class {
|
|
|
3940
4112
|
}
|
|
3941
4113
|
try {
|
|
3942
4114
|
const topN = matches.slice(0, 10);
|
|
3943
|
-
const
|
|
3944
|
-
|
|
3945
|
-
Return the result as a comma-separated list of document indices in order of relevance, from most relevant to least relevant.
|
|
3946
|
-
Use the indices provided in brackets like [0], [1], etc.
|
|
3947
|
-
Only return the indices (e.g., "2,0,1"), nothing else. Do not include brackets in the output.
|
|
3948
|
-
|
|
3949
|
-
Query: "${query}"
|
|
4115
|
+
const response = await llm.chat(
|
|
4116
|
+
[{ role: "user", content: `Query: "${query}"
|
|
3950
4117
|
|
|
3951
4118
|
Documents:
|
|
3952
|
-
${topN.map((m, i) => `[${i}] ${m.content.replace(/\n/g, " ")}`).join("\n")}
|
|
3953
|
-
const response = await llm.chat(
|
|
3954
|
-
[{ role: "user", content: prompt }],
|
|
4119
|
+
${topN.map((m, i) => `[${i}] ${m.content.replace(/\n/g, " ")}`).join("\n")}` }],
|
|
3955
4120
|
"",
|
|
3956
|
-
{
|
|
4121
|
+
{
|
|
4122
|
+
systemPrompt: 'You are a relevance ranking expert. Given the user query and a list of retrieved document chunks, rank the chunks by relevance to the query. Return the result as a comma-separated list of document indices in order of relevance, from most relevant to least relevant. Use the indices provided in brackets like [0], [1], etc. Only return the indices (e.g., "2,0,1"), nothing else. Do not include brackets in the output.',
|
|
4123
|
+
temperature: 0,
|
|
4124
|
+
maxTokens: 50
|
|
4125
|
+
}
|
|
3957
4126
|
);
|
|
3958
4127
|
const cleanedResponse = response.trim().replace(/[\[\]\s]/g, "");
|
|
3959
4128
|
const rankedIndices = cleanedResponse.split(",").map(Number).filter((n) => !isNaN(n));
|
|
@@ -4465,6 +4634,18 @@ var QueryProcessor = class {
|
|
|
4465
4634
|
}, normalizedField ? { field: normalizedField } : {}));
|
|
4466
4635
|
}
|
|
4467
4636
|
};
|
|
4637
|
+
const activeValidFields = validFields.length > 0 ? validFields : ["brand", "category", "price", "rating", "stock", "stock_quantity", "status", "name", "title"];
|
|
4638
|
+
const resolveValidField = (fieldStr) => {
|
|
4639
|
+
const cleaned = this.normalizeHintValue(fieldStr).replace(/\b(?:provide|show|get|give|list|all|the|a|an|of|organizations?|companies?|records?|items?|whose|with|having|where|that|which|have|has|is|are|was|were)\b/gi, " ").replace(/\s+/g, " ").trim();
|
|
4640
|
+
const comparable = (v) => v.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
4641
|
+
const cleanedComparable = comparable(cleaned);
|
|
4642
|
+
if (!cleanedComparable) return null;
|
|
4643
|
+
const matchedField = activeValidFields.find((fieldName) => {
|
|
4644
|
+
const candidate = comparable(fieldName);
|
|
4645
|
+
return candidate === cleanedComparable || candidate.includes(cleanedComparable) || cleanedComparable.includes(candidate);
|
|
4646
|
+
});
|
|
4647
|
+
return matchedField != null ? matchedField : null;
|
|
4648
|
+
};
|
|
4468
4649
|
for (const match of question.matchAll(/["']([^"']{2,100})["']/g)) {
|
|
4469
4650
|
addHint(match[1]);
|
|
4470
4651
|
}
|
|
@@ -4489,7 +4670,13 @@ var QueryProcessor = class {
|
|
|
4489
4670
|
const field = match[1];
|
|
4490
4671
|
const value = match[2];
|
|
4491
4672
|
if (field && !this.isLikelyPromptPhrase(field)) {
|
|
4492
|
-
|
|
4673
|
+
const resolvedField = resolveValidField(field);
|
|
4674
|
+
if (resolvedField) {
|
|
4675
|
+
addHint(value, resolvedField);
|
|
4676
|
+
} else {
|
|
4677
|
+
addHint(value);
|
|
4678
|
+
addHint(field);
|
|
4679
|
+
}
|
|
4493
4680
|
}
|
|
4494
4681
|
}
|
|
4495
4682
|
if (validFields.length > 0) {
|
|
@@ -4535,12 +4722,16 @@ var QueryProcessor = class {
|
|
|
4535
4722
|
];
|
|
4536
4723
|
for (const pattern of fieldValuePatterns) {
|
|
4537
4724
|
for (const match of question.matchAll(pattern)) {
|
|
4538
|
-
const field =
|
|
4725
|
+
const field = (_c = match[1]) != null ? _c : "";
|
|
4539
4726
|
const value = (_d = match[2]) != null ? _d : "";
|
|
4540
|
-
|
|
4541
|
-
|
|
4727
|
+
const resolvedField = resolveValidField(field);
|
|
4728
|
+
if (resolvedField) {
|
|
4729
|
+
addHint(value, resolvedField);
|
|
4542
4730
|
} else {
|
|
4543
4731
|
addHint(value);
|
|
4732
|
+
if (field && !this.isLikelyPromptPhrase(field)) {
|
|
4733
|
+
addHint(field);
|
|
4734
|
+
}
|
|
4544
4735
|
}
|
|
4545
4736
|
}
|
|
4546
4737
|
}
|
|
@@ -4767,7 +4958,7 @@ var LLMRouter = class {
|
|
|
4767
4958
|
|
|
4768
4959
|
// src/utils/UITransformer.ts
|
|
4769
4960
|
init_synonyms();
|
|
4770
|
-
var UITransformer = class {
|
|
4961
|
+
var UITransformer = class _UITransformer {
|
|
4771
4962
|
// ─── Public Entry Points ─────────────────────────────────────────────────
|
|
4772
4963
|
/**
|
|
4773
4964
|
* Heuristic-only transform (no LLM required).
|
|
@@ -4829,7 +5020,7 @@ var UITransformer = class {
|
|
|
4829
5020
|
static async analyzeAndDecide(query, sources, llm) {
|
|
4830
5021
|
let intent;
|
|
4831
5022
|
try {
|
|
4832
|
-
intent = await this.detectIntent(query, llm);
|
|
5023
|
+
intent = await this.detectIntent(query, llm, sources);
|
|
4833
5024
|
console.debug("[UITransformer] Detected intent:", intent);
|
|
4834
5025
|
} catch (err) {
|
|
4835
5026
|
console.warn("[UITransformer] Intent detection failed; using heuristic.", err);
|
|
@@ -4847,11 +5038,23 @@ var UITransformer = class {
|
|
|
4847
5038
|
try {
|
|
4848
5039
|
const context = this.buildContextSummary(sources);
|
|
4849
5040
|
const systemPrompt = this.buildVisualizationSystemPrompt();
|
|
5041
|
+
const profile = this.profileData(sources);
|
|
5042
|
+
const schemaContext = `
|
|
5043
|
+
RETRIEVED DATA SCHEMA:
|
|
5044
|
+
- Numeric fields (measures): ${profile.numericFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
|
|
5045
|
+
- Category fields (dimensions): ${profile.categoricalFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
|
|
5046
|
+
- Date fields (temporal): ${profile.dateFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
|
|
5047
|
+
- Boolean fields: ${profile.booleanFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
|
|
5048
|
+
- Text/Other fields: ${profile.fields.filter((f) => f.kind === "text").map((f) => f.key).join(", ") || "None"}
|
|
5049
|
+
`;
|
|
4850
5050
|
const userPrompt = [
|
|
4851
5051
|
`USER QUESTION: ${query}`,
|
|
4852
5052
|
"",
|
|
4853
5053
|
`DETECTED INTENT (JSON): ${JSON.stringify(intent)}`,
|
|
4854
5054
|
"",
|
|
5055
|
+
`RETRIEVED DATA SCHEMA:`,
|
|
5056
|
+
schemaContext,
|
|
5057
|
+
"",
|
|
4855
5058
|
"RETRIEVED DATA (JSON):",
|
|
4856
5059
|
context
|
|
4857
5060
|
].join("\n");
|
|
@@ -4862,6 +5065,20 @@ var UITransformer = class {
|
|
|
4862
5065
|
);
|
|
4863
5066
|
const parsed = this.parseTransformationResponse(rawResponse);
|
|
4864
5067
|
if (parsed) {
|
|
5068
|
+
let isCompatible = true;
|
|
5069
|
+
if (parsed.type === "line_chart" && (profile.dateFields.length === 0 || profile.numericFields.length === 0)) {
|
|
5070
|
+
isCompatible = false;
|
|
5071
|
+
} else if (["bar_chart", "horizontal_bar", "pie_chart", "donut_chart"].includes(parsed.type) && (profile.categoricalFields.length === 0 && profile.numericFields.length === 0)) {
|
|
5072
|
+
isCompatible = false;
|
|
5073
|
+
} else if (parsed.type === "scatter_plot" && profile.numericFields.length < 2) {
|
|
5074
|
+
isCompatible = false;
|
|
5075
|
+
} else if (parsed.type === "metric_card" && profile.numericFields.length === 0) {
|
|
5076
|
+
isCompatible = false;
|
|
5077
|
+
}
|
|
5078
|
+
if (!isCompatible) {
|
|
5079
|
+
console.warn(`[UITransformer] LLM chose incompatible visualization type "${parsed.type}" for retrieved schema. Falling back to heuristic.`);
|
|
5080
|
+
return this.transform(query, sources, void 0, void 0, intent);
|
|
5081
|
+
}
|
|
4865
5082
|
const intentAllowsTable = intent.wantsExplicitTable || ["tabular", "table", "geographic"].includes(intent.visualizationHint);
|
|
4866
5083
|
const intentWantsPieLikeChart = ["pie_chart", "donut_chart"].includes(intent.recommendedChart) || ["composition", "category_breakdown"].includes(intent.visualizationHint);
|
|
4867
5084
|
if (parsed.type === "table" && !intentAllowsTable) {
|
|
@@ -4891,7 +5108,26 @@ var UITransformer = class {
|
|
|
4891
5108
|
* - The intent object can be reused across both the heuristic and LLM paths.
|
|
4892
5109
|
* - It is easy to unit-test intent detection in isolation.
|
|
4893
5110
|
*/
|
|
4894
|
-
static async detectIntent(query, llm) {
|
|
5111
|
+
static async detectIntent(query, llm, sources) {
|
|
5112
|
+
let schemaProfileText = "";
|
|
5113
|
+
if (sources && sources.length > 0) {
|
|
5114
|
+
const profile = this.profileData(sources);
|
|
5115
|
+
const hasProducts = sources.some((item) => this.isProductData(item));
|
|
5116
|
+
schemaProfileText = `
|
|
5117
|
+
RETRIEVED DATA SCHEMA:
|
|
5118
|
+
- Numeric fields (measures): ${profile.numericFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
|
|
5119
|
+
- Category fields (dimensions): ${profile.categoricalFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
|
|
5120
|
+
- Date fields (temporal): ${profile.dateFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
|
|
5121
|
+
- Boolean fields: ${profile.booleanFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
|
|
5122
|
+
- Text fields: ${profile.fields.filter((f) => f.kind === "text").map((f) => f.key).join(", ") || "None"}
|
|
5123
|
+
|
|
5124
|
+
Please choose visualizationHint and recommendedChart dynamically based on the available schema.
|
|
5125
|
+
- Do NOT recommend "trend" or "line_chart" if there are no Date fields.
|
|
5126
|
+
- Do NOT recommend numeric-dependent visualizations (like bar_chart, line_chart, pie_chart, scatter_plot, histogram, metric_card) if there are no Numeric fields. Fall back to tabular/table or text.
|
|
5127
|
+
- If there are multiple metadata fields but no clear categories or numbers, "tabular"/"table" is a highly accurate default.
|
|
5128
|
+
${hasProducts ? `- Note: The retrieved data matches product/catalog structure. If the user query is looking for, exploring, searching, browsing, or listing products/items, you MUST recommend visualizationHint: "product_browse" and recommendedChart: "text".` : ""}
|
|
5129
|
+
`;
|
|
5130
|
+
}
|
|
4895
5131
|
const systemPrompt = `You are an intent classifier for a product-search RAG system.
|
|
4896
5132
|
Given a user query, return ONLY a valid JSON object with this exact shape \u2014 no prose, no markdown:
|
|
4897
5133
|
|
|
@@ -4927,8 +5163,11 @@ RULES:
|
|
|
4927
5163
|
- isTemporal: true if time words appear (trend, historical, over time, last year, monthly, etc.)
|
|
4928
5164
|
- isComparison: true if user compares, ranks, or contrasts entities or categories.
|
|
4929
5165
|
- language: detect from the query text itself; default "en" if uncertain.`;
|
|
5166
|
+
const userPrompt = `QUERY: ${query}${schemaProfileText ? `
|
|
5167
|
+
|
|
5168
|
+
${schemaProfileText}` : ""}`;
|
|
4930
5169
|
const rawResponse = await llm.chat(
|
|
4931
|
-
[{ role: "user", content:
|
|
5170
|
+
[{ role: "user", content: userPrompt }],
|
|
4932
5171
|
"",
|
|
4933
5172
|
{ systemPrompt, temperature: 0 }
|
|
4934
5173
|
);
|
|
@@ -5371,10 +5610,21 @@ RULES:
|
|
|
5371
5610
|
const hasEntityTerms = /\b(organization|organisations?|organizations?|company|companies|employee|employees|staff|headcount|workforce)\b/.test(q);
|
|
5372
5611
|
return asksForRecords && (hasNumericPredicate || hasEntityTerms);
|
|
5373
5612
|
}
|
|
5613
|
+
/** @internal kept private for transform() internal logic */
|
|
5374
5614
|
static isProductQuery(query) {
|
|
5615
|
+
return _UITransformer._productQueryTest(query);
|
|
5616
|
+
}
|
|
5617
|
+
/**
|
|
5618
|
+
* Public entry-point for external callers (e.g. Pipeline)
|
|
5619
|
+
* to check whether a query maps to product_browse without triggering an LLM call.
|
|
5620
|
+
*/
|
|
5621
|
+
static isProductQueryPublic(query) {
|
|
5622
|
+
return _UITransformer._productQueryTest(query);
|
|
5623
|
+
}
|
|
5624
|
+
static _productQueryTest(query) {
|
|
5375
5625
|
const q = query.toLowerCase();
|
|
5376
5626
|
const productTerms = /\b(product|products|item|items|sku|catalog|catalogue|price|prices|brand|model|stock|inventory|in stock|out of stock|buy|shop)\b/.test(q);
|
|
5377
|
-
const productAction = /\b(recommend|suggest|describe|description|detail|details|about|show|find|search|browse|list)\b/.test(q);
|
|
5627
|
+
const productAction = /\b(recommend|suggest|describe|description|detail|details|about|show|find|search|browse|list|explore|exploring)\b/.test(q);
|
|
5378
5628
|
const nonProductEntityTerms = /\b(organization|organisations?|organizations?|company|companies|employee|employees|staff|headcount|workforce)\b/.test(q);
|
|
5379
5629
|
return productTerms && productAction && !nonProductEntityTerms;
|
|
5380
5630
|
}
|
|
@@ -6147,23 +6397,19 @@ function estimateCostUsd(promptTokens, completionTokens, model) {
|
|
|
6147
6397
|
async function scoreHallucination(llm, answer, context) {
|
|
6148
6398
|
const maxContextChars = 3e3;
|
|
6149
6399
|
const truncatedContext = context.length > maxContextChars ? context.slice(0, maxContextChars) + "\n...[truncated]" : context;
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
CONTEXT:
|
|
6400
|
+
try {
|
|
6401
|
+
const raw = await llm.chat(
|
|
6402
|
+
[{ role: "user", content: `CONTEXT:
|
|
6153
6403
|
${truncatedContext}
|
|
6154
6404
|
|
|
6155
6405
|
ANSWER:
|
|
6156
|
-
${answer}
|
|
6157
|
-
|
|
6158
|
-
Return ONLY a valid JSON object with no markdown fences:
|
|
6159
|
-
{"score": <float 0-1>, "reason": "<one sentence>"}
|
|
6160
|
-
|
|
6161
|
-
Where score 0 = fully grounded in context, score 1 = likely hallucinated or unsupported.`;
|
|
6162
|
-
try {
|
|
6163
|
-
const raw = await llm.chat(
|
|
6164
|
-
[{ role: "user", content: prompt }],
|
|
6406
|
+
${answer}` }],
|
|
6165
6407
|
"",
|
|
6166
|
-
{
|
|
6408
|
+
{
|
|
6409
|
+
systemPrompt: 'You are an AI quality checker. Given the CONTEXT retrieved from a knowledge base and the ANSWER generated from it, rate how well-grounded the answer is. Return ONLY a valid JSON object with no markdown fences: {"score": <float 0-1>, "reason": "<one sentence>"} where score 0 = fully grounded in context, score 1 = likely hallucinated or unsupported.',
|
|
6410
|
+
temperature: 0,
|
|
6411
|
+
maxTokens: 120
|
|
6412
|
+
}
|
|
6167
6413
|
);
|
|
6168
6414
|
const jsonMatch = raw.match(/\{[\s\S]*\}/);
|
|
6169
6415
|
if (!jsonMatch) return void 0;
|
|
@@ -6223,7 +6469,10 @@ var Pipeline = class {
|
|
|
6223
6469
|
- For product descriptions, summarize customer-facing details only. Do NOT list internal catalog fields such as Handle, Body (HTML), Vendor, Type, Tags, Published, Option, Variant, SKU, or raw metadata labels.
|
|
6224
6470
|
- Do NOT try to format product lists as tables.
|
|
6225
6471
|
`;
|
|
6226
|
-
this.config.llm.systemPrompt
|
|
6472
|
+
const userPromptPrefix = this.config.llm.systemPrompt ? `${this.config.llm.systemPrompt}
|
|
6473
|
+
|
|
6474
|
+
` : "";
|
|
6475
|
+
this.config.llm.systemPrompt = `${userPromptPrefix}${chartInstruction}`;
|
|
6227
6476
|
this.vectorDB = await ProviderRegistry.createVectorProvider(this.config.vectorDb);
|
|
6228
6477
|
this.llmRouter = new LLMRouter(this.config);
|
|
6229
6478
|
const { llmProvider: resolvedLLM, embeddingProvider } = await EmbeddingStrategyResolver.resolve(
|
|
@@ -6401,11 +6650,11 @@ var Pipeline = class {
|
|
|
6401
6650
|
*/
|
|
6402
6651
|
askStream(_0) {
|
|
6403
6652
|
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
6404
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
6653
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v;
|
|
6405
6654
|
yield new __await(this.initialize());
|
|
6406
6655
|
const ns = namespace != null ? namespace : this.config.projectId;
|
|
6407
6656
|
const topK = (_b = (_a = this.config.rag) == null ? void 0 : _a.topK) != null ? _b : 5;
|
|
6408
|
-
const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0;
|
|
6657
|
+
const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0.3;
|
|
6409
6658
|
const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
6410
6659
|
const requestStart = performance.now();
|
|
6411
6660
|
try {
|
|
@@ -6424,12 +6673,13 @@ var Pipeline = class {
|
|
|
6424
6673
|
const embedStart = performance.now();
|
|
6425
6674
|
const cacheKey = `${ns}::${searchQuery}`;
|
|
6426
6675
|
const cachedVector = this.embeddingCache.get(cacheKey);
|
|
6676
|
+
const useGraph = this.graphDB && ((_h = this.config.rag) == null ? void 0 : _h.useGraphRetrieval);
|
|
6427
6677
|
const [strategyResult, embeddedVector] = yield new __await(Promise.all([
|
|
6428
6678
|
QueryProcessor.determineRetrievalStrategy(
|
|
6429
6679
|
searchQuery,
|
|
6430
|
-
this.llmRouter.get("fast"),
|
|
6431
|
-
(
|
|
6432
|
-
(
|
|
6680
|
+
useGraph ? this.llmRouter.get("fast") : void 0,
|
|
6681
|
+
(_i = this.config.rag) == null ? void 0 : _i.graphKeywords,
|
|
6682
|
+
(_j = this.config.rag) == null ? void 0 : _j.vectorKeywords
|
|
6433
6683
|
),
|
|
6434
6684
|
// Embed immediately regardless of strategy — costs nothing if cached.
|
|
6435
6685
|
// If strategy turns out to be 'graph'-only we just won't use the vector.
|
|
@@ -6439,7 +6689,7 @@ var Pipeline = class {
|
|
|
6439
6689
|
if (!cachedVector && queryVector.length > 0) {
|
|
6440
6690
|
this.embeddingCache.set(cacheKey, queryVector);
|
|
6441
6691
|
}
|
|
6442
|
-
const graphData = (strategyResult === "graph" || strategyResult === "both") && this.graphDB && ((
|
|
6692
|
+
const graphData = (strategyResult === "graph" || strategyResult === "both") && this.graphDB && ((_k = this.config.rag) == null ? void 0 : _k.useGraphRetrieval) ? yield new __await(this.graphDB.query(searchQuery)) : void 0;
|
|
6443
6693
|
const hasMetadataFilter = filter.metadata && Object.keys(filter.metadata).length > 0;
|
|
6444
6694
|
const hasNumericPredicates = Array.isArray(filter.__numericPredicates) && filter.__numericPredicates.length > 0;
|
|
6445
6695
|
const wantsExhaustiveList = hasNumericPredicates || hasMetadataFilter || /\b(list|all|show|provide|give|get|browse|find|search|display)\b/i.test(question);
|
|
@@ -6452,7 +6702,7 @@ var Pipeline = class {
|
|
|
6452
6702
|
const structuredSources = this.applyStructuredFilters(rawSources, filter);
|
|
6453
6703
|
let fullSources = hasNumericPredicates ? structuredSources : structuredSources.filter((m) => m.score >= scoreThreshold);
|
|
6454
6704
|
const rerankLimit = wantsExhaustiveList ? retrievalLimit : topK;
|
|
6455
|
-
if (!hasNumericPredicates && ((
|
|
6705
|
+
if (!hasNumericPredicates && ((_l = this.config.rag) == null ? void 0 : _l.useReranking)) {
|
|
6456
6706
|
fullSources = yield new __await(this.reranker.rerank(fullSources, question, rerankLimit));
|
|
6457
6707
|
} else if (!wantsExhaustiveList) {
|
|
6458
6708
|
fullSources = fullSources.slice(0, topK);
|
|
@@ -6464,7 +6714,8 @@ ${m.content}`).join("\n\n---\n\n") : "No relevant context found.";
|
|
|
6464
6714
|
if (hasMetadataFilter) {
|
|
6465
6715
|
displayCount = fullSources.length;
|
|
6466
6716
|
} else {
|
|
6467
|
-
const
|
|
6717
|
+
const baseThreshold = Math.max(scoreThreshold, 0.4);
|
|
6718
|
+
const highlyRelevant = fullSources.filter((m) => m.score >= baseThreshold);
|
|
6468
6719
|
displayCount = Math.max(highlyRelevant.length, topK);
|
|
6469
6720
|
if (displayCount > 15) {
|
|
6470
6721
|
displayCount = 15;
|
|
@@ -6482,34 +6733,117 @@ VECTOR CONTEXT:
|
|
|
6482
6733
|
${context}`;
|
|
6483
6734
|
}
|
|
6484
6735
|
const allMetadataKeys = Array.from(new Set(sources.flatMap((s) => Object.keys(s.metadata || {}))));
|
|
6485
|
-
const
|
|
6486
|
-
|
|
6487
|
-
(
|
|
6736
|
+
const cachedSchema = allMetadataKeys.length > 0 ? SchemaMapper.getCached(ns, allMetadataKeys) : void 0;
|
|
6737
|
+
if (allMetadataKeys.length > 0 && !cachedSchema) {
|
|
6738
|
+
SchemaMapper.train(this.llmProvider, ns, allMetadataKeys).catch(() => {
|
|
6739
|
+
});
|
|
6740
|
+
}
|
|
6741
|
+
const isProductQ = UITransformer.isProductQueryPublic(question);
|
|
6742
|
+
const uiTransformationPromise = isProductQ ? Promise.resolve(
|
|
6743
|
+
UITransformer.transform(
|
|
6488
6744
|
question,
|
|
6489
6745
|
sources,
|
|
6490
|
-
|
|
6491
|
-
|
|
6746
|
+
this.config,
|
|
6747
|
+
cachedSchema,
|
|
6748
|
+
{ visualizationHint: "product_browse", recommendedChart: "text", filterInStockOnly: false, wantsExplicitTable: false, isTemporal: false, isComparison: false, language: "en" }
|
|
6492
6749
|
)
|
|
6750
|
+
) : this.generateUiTransformation(
|
|
6751
|
+
question,
|
|
6752
|
+
sources,
|
|
6753
|
+
cachedSchema,
|
|
6754
|
+
hasNumericPredicates
|
|
6493
6755
|
).catch((uiError) => {
|
|
6494
6756
|
console.warn("[Pipeline] UI transformation failed concurrently:", uiError);
|
|
6495
|
-
return UITransformer.transform(question, sources, this.config);
|
|
6757
|
+
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6496
6758
|
});
|
|
6759
|
+
let hallucinationScoringPromise = Promise.resolve(void 0);
|
|
6497
6760
|
const restrictionSuffix = "\n\n(IMPORTANT: Format your response beautifully using rich Markdown! Use bolding for emphasis, headings (##) for structure, bullet points for lists, and proper line breaks between paragraphs to make it highly readable. However, NEVER generate Markdown tables, HTML figures, or text charts (the UI renders requested charts separately, so NEVER say you cannot create, display, draw, render, or provide a chart/visualization). If listing products, use simple markdown bullet points or comma-separated names. NEVER use plus signs (+) to separate product names, category names, or list items. For product description/detail questions, provide customer-facing prose only and do NOT list internal catalog fields such as Handle, Body (HTML), Vendor, Type, Tags, Published, Option, Variant, SKU, or raw metadata labels. You CAN use numbers for years/counts like 2006 or 5800, but NEVER put a dollar sign ($) before them.)";
|
|
6761
|
+
const isClaude37 = this.config.llm.model.includes("claude-3-7-sonnet");
|
|
6762
|
+
const isNativeThinking = isClaude37 && (((_m = this.config.llm.options) == null ? void 0 : _m.thinking) === true || ((_n = this.config.llm.options) == null ? void 0 : _n.thinking) === "enabled" || ((_o = this.config.llm.options) == null ? void 0 : _o.thinking) !== false);
|
|
6763
|
+
const modelNameLower = this.config.llm.model.toLowerCase();
|
|
6764
|
+
const isReasoningModel = modelNameLower.includes("-r1") || modelNameLower.includes("deepseek-r1") || modelNameLower.includes("reasoning") || modelNameLower.includes("thinking");
|
|
6765
|
+
const isSimulatedThinking = !isNativeThinking && (((_p = this.config.llm.options) == null ? void 0 : _p.thinking) === true || ((_q = this.config.llm.options) == null ? void 0 : _q.thinking) === "enabled" || isReasoningModel && ((_r = this.config.llm.options) == null ? void 0 : _r.thinking) !== false);
|
|
6766
|
+
let finalRestrictionSuffix = restrictionSuffix;
|
|
6767
|
+
if (isSimulatedThinking) {
|
|
6768
|
+
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.`)";
|
|
6769
|
+
}
|
|
6498
6770
|
const hardenedHistory = [...history];
|
|
6499
|
-
const userQuestion = { role: "user", content: question +
|
|
6771
|
+
const userQuestion = { role: "user", content: question + finalRestrictionSuffix };
|
|
6500
6772
|
const messages = [...hardenedHistory, userQuestion];
|
|
6501
|
-
const systemPrompt = (
|
|
6773
|
+
const systemPrompt = (_s = this.config.llm.systemPrompt) != null ? _s : "";
|
|
6502
6774
|
const userPrompt = messages.map((m) => `${m.role}: ${m.content}`).join("\n");
|
|
6503
6775
|
let fullReply = "";
|
|
6776
|
+
let thinkingText = "";
|
|
6777
|
+
let thinkingStartMs = performance.now();
|
|
6778
|
+
let thinkingDurationMs = 0;
|
|
6504
6779
|
const generateStart = performance.now();
|
|
6505
6780
|
if (this.llmProvider.chatStream) {
|
|
6506
6781
|
const stream = this.llmProvider.chatStream(messages, context);
|
|
6507
6782
|
if (!stream) throw new Error(`[Pipeline] ${this.config.llm.provider} chatStream returned undefined`);
|
|
6783
|
+
let inThinking = false;
|
|
6784
|
+
let textBuffer = "";
|
|
6508
6785
|
try {
|
|
6509
6786
|
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
6510
6787
|
const chunk = temp.value;
|
|
6511
|
-
|
|
6512
|
-
|
|
6788
|
+
if (chunk.startsWith("\0THINKING\0")) {
|
|
6789
|
+
const thinkingDelta = chunk.slice("\0THINKING\0".length);
|
|
6790
|
+
thinkingText += thinkingDelta;
|
|
6791
|
+
thinkingDurationMs = performance.now() - thinkingStartMs;
|
|
6792
|
+
yield { type: "thinking", text: thinkingDelta };
|
|
6793
|
+
continue;
|
|
6794
|
+
}
|
|
6795
|
+
if (isSimulatedThinking) {
|
|
6796
|
+
textBuffer += chunk;
|
|
6797
|
+
while (textBuffer.length > 0) {
|
|
6798
|
+
if (!inThinking) {
|
|
6799
|
+
const thinkIndex = textBuffer.indexOf("<think>");
|
|
6800
|
+
if (thinkIndex !== -1) {
|
|
6801
|
+
const before = textBuffer.slice(0, thinkIndex);
|
|
6802
|
+
if (before) {
|
|
6803
|
+
fullReply += before;
|
|
6804
|
+
yield before;
|
|
6805
|
+
}
|
|
6806
|
+
inThinking = true;
|
|
6807
|
+
thinkingStartMs = performance.now();
|
|
6808
|
+
textBuffer = textBuffer.slice(thinkIndex + "<think>".length);
|
|
6809
|
+
} else {
|
|
6810
|
+
const maxSafeLength = textBuffer.length - "<think>".length;
|
|
6811
|
+
if (maxSafeLength > 0) {
|
|
6812
|
+
const safeText = textBuffer.slice(0, maxSafeLength);
|
|
6813
|
+
fullReply += safeText;
|
|
6814
|
+
yield safeText;
|
|
6815
|
+
textBuffer = textBuffer.slice(maxSafeLength);
|
|
6816
|
+
}
|
|
6817
|
+
break;
|
|
6818
|
+
}
|
|
6819
|
+
} else {
|
|
6820
|
+
const endThinkIndex = textBuffer.indexOf("</think>");
|
|
6821
|
+
if (endThinkIndex !== -1) {
|
|
6822
|
+
const thinkingDelta = textBuffer.slice(0, endThinkIndex);
|
|
6823
|
+
if (thinkingDelta) {
|
|
6824
|
+
thinkingText += thinkingDelta;
|
|
6825
|
+
thinkingDurationMs = performance.now() - thinkingStartMs;
|
|
6826
|
+
yield { type: "thinking", text: thinkingDelta };
|
|
6827
|
+
}
|
|
6828
|
+
inThinking = false;
|
|
6829
|
+
textBuffer = textBuffer.slice(endThinkIndex + "</think>".length);
|
|
6830
|
+
} else {
|
|
6831
|
+
const maxSafeLength = textBuffer.length - "</think>".length;
|
|
6832
|
+
if (maxSafeLength > 0) {
|
|
6833
|
+
const thinkingDelta = textBuffer.slice(0, maxSafeLength);
|
|
6834
|
+
thinkingText += thinkingDelta;
|
|
6835
|
+
thinkingDurationMs = performance.now() - thinkingStartMs;
|
|
6836
|
+
yield { type: "thinking", text: thinkingDelta };
|
|
6837
|
+
textBuffer = textBuffer.slice(maxSafeLength);
|
|
6838
|
+
}
|
|
6839
|
+
break;
|
|
6840
|
+
}
|
|
6841
|
+
}
|
|
6842
|
+
}
|
|
6843
|
+
} else {
|
|
6844
|
+
fullReply += chunk;
|
|
6845
|
+
yield chunk;
|
|
6846
|
+
}
|
|
6513
6847
|
}
|
|
6514
6848
|
} catch (temp) {
|
|
6515
6849
|
error = [temp];
|
|
@@ -6521,17 +6855,42 @@ ${context}`;
|
|
|
6521
6855
|
throw error[0];
|
|
6522
6856
|
}
|
|
6523
6857
|
}
|
|
6858
|
+
if (isSimulatedThinking && textBuffer.length > 0) {
|
|
6859
|
+
if (inThinking) {
|
|
6860
|
+
thinkingText += textBuffer;
|
|
6861
|
+
yield { type: "thinking", text: textBuffer };
|
|
6862
|
+
} else {
|
|
6863
|
+
fullReply += textBuffer;
|
|
6864
|
+
yield textBuffer;
|
|
6865
|
+
}
|
|
6866
|
+
}
|
|
6524
6867
|
} else {
|
|
6525
6868
|
const reply = yield new __await(this.llmProvider.chat(messages, context));
|
|
6526
|
-
|
|
6527
|
-
|
|
6869
|
+
if (isSimulatedThinking) {
|
|
6870
|
+
const thinkStart = reply.indexOf("<think>");
|
|
6871
|
+
const thinkEnd = reply.indexOf("</think>");
|
|
6872
|
+
if (thinkStart !== -1 && thinkEnd !== -1 && thinkEnd > thinkStart) {
|
|
6873
|
+
thinkingText = reply.slice(thinkStart + "<think>".length, thinkEnd);
|
|
6874
|
+
fullReply = reply.slice(0, thinkStart) + reply.slice(thinkEnd + "</think>".length);
|
|
6875
|
+
thinkingDurationMs = 100;
|
|
6876
|
+
} else {
|
|
6877
|
+
fullReply = reply;
|
|
6878
|
+
}
|
|
6879
|
+
} else {
|
|
6880
|
+
fullReply = reply;
|
|
6881
|
+
}
|
|
6882
|
+
yield fullReply;
|
|
6883
|
+
}
|
|
6884
|
+
const runHallucination = ((_t = this.config.llm.options) == null ? void 0 : _t.hallucinationScoring) === true || this.config.llm.provider !== "ollama" && ((_u = this.config.llm.options) == null ? void 0 : _u.hallucinationScoring) !== false;
|
|
6885
|
+
if (runHallucination) {
|
|
6886
|
+
hallucinationScoringPromise = scoreHallucination(this.llmProvider, fullReply, context).catch(() => void 0);
|
|
6528
6887
|
}
|
|
6529
6888
|
const generateMs = performance.now() - generateStart;
|
|
6530
6889
|
const totalMs = performance.now() - requestStart;
|
|
6531
6890
|
const latency = {
|
|
6532
6891
|
embedMs: Math.round(embedMs),
|
|
6533
6892
|
retrieveMs: Math.round(retrieveMs),
|
|
6534
|
-
rerankMs: ((
|
|
6893
|
+
rerankMs: ((_v = this.config.rag) == null ? void 0 : _v.useReranking) ? Math.round(rerankMs) : void 0,
|
|
6535
6894
|
generateMs: Math.round(generateMs),
|
|
6536
6895
|
totalMs: Math.round(totalMs)
|
|
6537
6896
|
};
|
|
@@ -6544,12 +6903,16 @@ ${context}`;
|
|
|
6544
6903
|
totalTokens: promptTokens + completionTokens,
|
|
6545
6904
|
estimatedCostUsd: estimateCostUsd(promptTokens, completionTokens, this.config.llm.model)
|
|
6546
6905
|
};
|
|
6547
|
-
const
|
|
6906
|
+
const [uiTransformation, hallucinationResult] = yield new __await(Promise.all([
|
|
6907
|
+
uiTransformationPromise,
|
|
6908
|
+
hallucinationScoringPromise
|
|
6909
|
+
]));
|
|
6910
|
+
const trace = __spreadValues({
|
|
6548
6911
|
requestId,
|
|
6549
6912
|
query: question,
|
|
6550
6913
|
rewrittenQuery,
|
|
6551
6914
|
systemPrompt,
|
|
6552
|
-
userPrompt: question +
|
|
6915
|
+
userPrompt: question + finalRestrictionSuffix,
|
|
6553
6916
|
chunks: sources.map((s) => {
|
|
6554
6917
|
var _a2;
|
|
6555
6918
|
return {
|
|
@@ -6563,22 +6926,19 @@ ${context}`;
|
|
|
6563
6926
|
latency,
|
|
6564
6927
|
tokens,
|
|
6565
6928
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6566
|
-
}
|
|
6567
|
-
|
|
6929
|
+
}, hallucinationResult ? {
|
|
6930
|
+
hallucinationScore: hallucinationResult.score,
|
|
6931
|
+
hallucinationReason: hallucinationResult.reason
|
|
6932
|
+
} : {});
|
|
6568
6933
|
yield {
|
|
6569
6934
|
reply: "",
|
|
6570
6935
|
sources,
|
|
6571
6936
|
graphData,
|
|
6572
6937
|
ui_transformation: uiTransformation,
|
|
6573
|
-
trace
|
|
6938
|
+
trace,
|
|
6939
|
+
thinking: thinkingText || void 0,
|
|
6940
|
+
thinkingMs: thinkingDurationMs > 0 ? Math.round(thinkingDurationMs) : void 0
|
|
6574
6941
|
};
|
|
6575
|
-
scoreHallucination(this.llmProvider, fullReply, context).then((hallucinationResult) => {
|
|
6576
|
-
if (hallucinationResult) {
|
|
6577
|
-
trace.hallucinationScore = hallucinationResult.score;
|
|
6578
|
-
trace.hallucinationReason = hallucinationResult.reason;
|
|
6579
|
-
}
|
|
6580
|
-
}).catch(() => {
|
|
6581
|
-
});
|
|
6582
6942
|
} catch (error2) {
|
|
6583
6943
|
throw new Error(`[Pipeline] Stream failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
6584
6944
|
}
|
|
@@ -6588,18 +6948,30 @@ ${context}`;
|
|
|
6588
6948
|
* Universal retrieval method combining all enabled providers.
|
|
6589
6949
|
* Uses an LRU-bounded embedding cache to avoid re-embedding the same query.
|
|
6590
6950
|
*/
|
|
6591
|
-
async generateUiTransformation(question, sources,
|
|
6951
|
+
async generateUiTransformation(question, sources, cachedSchema, forceDeterministic = false) {
|
|
6952
|
+
var _a;
|
|
6592
6953
|
if (!sources || sources.length === 0) {
|
|
6593
|
-
return UITransformer.transform(question, sources, this.config,
|
|
6954
|
+
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6594
6955
|
}
|
|
6595
|
-
if (
|
|
6596
|
-
return UITransformer.transform(
|
|
6956
|
+
if (UITransformer.isProductQueryPublic(question)) {
|
|
6957
|
+
return UITransformer.transform(
|
|
6958
|
+
question,
|
|
6959
|
+
sources,
|
|
6960
|
+
this.config,
|
|
6961
|
+
cachedSchema,
|
|
6962
|
+
{ visualizationHint: "product_browse", recommendedChart: "text", filterInStockOnly: false, wantsExplicitTable: false, isTemporal: false, isComparison: false, language: "en" }
|
|
6963
|
+
);
|
|
6964
|
+
}
|
|
6965
|
+
const isLocalProvider = this.config.llm.provider === "ollama";
|
|
6966
|
+
const disableLlmUiTransform = ((_a = this.config.llm.options) == null ? void 0 : _a.disableLlmUiTransform) === true;
|
|
6967
|
+
if (forceDeterministic || isLocalProvider || disableLlmUiTransform) {
|
|
6968
|
+
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6597
6969
|
}
|
|
6598
6970
|
try {
|
|
6599
6971
|
return await UITransformer.analyzeAndDecide(question, sources, this.llmRouter.get("fast"));
|
|
6600
6972
|
} catch (err) {
|
|
6601
6973
|
console.warn("[Pipeline] generateUiTransformation failed, using heuristic fallback:", err);
|
|
6602
|
-
return UITransformer.transform(question, sources, this.config,
|
|
6974
|
+
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6603
6975
|
}
|
|
6604
6976
|
}
|
|
6605
6977
|
applyStructuredFilters(sources, filter) {
|
|
@@ -6683,25 +7055,29 @@ ${context}`;
|
|
|
6683
7055
|
return Number.isFinite(numeric) ? numeric : null;
|
|
6684
7056
|
}
|
|
6685
7057
|
async retrieve(query, options) {
|
|
6686
|
-
var _a, _b, _c, _d, _e, _f;
|
|
7058
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
6687
7059
|
const ns = (_a = options.namespace) != null ? _a : this.config.projectId;
|
|
6688
7060
|
const topK = (_b = options.topK) != null ? _b : 5;
|
|
6689
7061
|
const cacheKey = `${ns}::${query}`;
|
|
6690
7062
|
let queryVector = this.embeddingCache.get(cacheKey);
|
|
6691
|
-
const
|
|
7063
|
+
const useGraph = this.graphDB && ((_c = this.config.rag) == null ? void 0 : _c.useGraphRetrieval);
|
|
7064
|
+
const strategy = await QueryProcessor.determineRetrievalStrategy(
|
|
7065
|
+
query,
|
|
7066
|
+
useGraph ? this.llmRouter.get("fast") : void 0
|
|
7067
|
+
);
|
|
6692
7068
|
console.debug(`[Pipeline] Determined retrieval strategy: ${strategy}`);
|
|
6693
7069
|
const [retrievedVector, graphData] = await Promise.all([
|
|
6694
7070
|
// Only embed if we need vector search (strategy is 'vector' or 'both')
|
|
6695
7071
|
strategy === "vector" || strategy === "both" ? queryVector ? Promise.resolve(queryVector) : this.embeddingProvider.embed(query, { taskType: "query" }) : Promise.resolve([]),
|
|
6696
7072
|
// Only query graph if we need graph search (strategy is 'graph' or 'both')
|
|
6697
|
-
(strategy === "graph" || strategy === "both") && this.graphDB && ((
|
|
7073
|
+
(strategy === "graph" || strategy === "both") && this.graphDB && ((_d = this.config.rag) == null ? void 0 : _d.useGraphRetrieval) ? this.graphDB.query(query) : Promise.resolve(void 0)
|
|
6698
7074
|
]);
|
|
6699
7075
|
if ((strategy === "vector" || strategy === "both") && !queryVector && retrievedVector && retrievedVector.length > 0) {
|
|
6700
7076
|
this.embeddingCache.set(cacheKey, retrievedVector);
|
|
6701
7077
|
queryVector = retrievedVector;
|
|
6702
7078
|
}
|
|
6703
|
-
const baseFilter = __spreadProps(__spreadValues({}, (
|
|
6704
|
-
const numericPredicates = QueryProcessor.extractNumericPredicates(query, (
|
|
7079
|
+
const baseFilter = __spreadProps(__spreadValues({}, (_e = options.filter) != null ? _e : {}), { queryText: query });
|
|
7080
|
+
const numericPredicates = QueryProcessor.extractNumericPredicates(query, (_f = this.config.rag) == null ? void 0 : _f.filterableFields);
|
|
6705
7081
|
if (numericPredicates.length > 0) {
|
|
6706
7082
|
baseFilter.__numericPredicates = numericPredicates;
|
|
6707
7083
|
}
|
|
@@ -6712,7 +7088,7 @@ ${context}`;
|
|
|
6712
7088
|
) : [];
|
|
6713
7089
|
const resolvedSources = [];
|
|
6714
7090
|
for (const source of sources) {
|
|
6715
|
-
const parentId = (
|
|
7091
|
+
const parentId = (_g = source.metadata) == null ? void 0 : _g.parent_id;
|
|
6716
7092
|
if (parentId) {
|
|
6717
7093
|
console.log(`[Pipeline] Multi-Vector: Found child chunk. Parent ID: ${parentId}`);
|
|
6718
7094
|
resolvedSources.push(source);
|
|
@@ -6735,10 +7111,13 @@ New Question: ${question}
|
|
|
6735
7111
|
Optimized Search Query:`;
|
|
6736
7112
|
const rewrite = await this.llmProvider.chat(
|
|
6737
7113
|
[
|
|
6738
|
-
{ role: "system", content: "You are an assistant that optimizes search queries for RAG systems." },
|
|
6739
7114
|
{ role: "user", content: prompt }
|
|
6740
7115
|
],
|
|
6741
|
-
""
|
|
7116
|
+
"",
|
|
7117
|
+
{
|
|
7118
|
+
systemPrompt: "You are an assistant that optimizes search queries for RAG systems. Focus on extracting the core intent and entities. Do not answer the question, just rewrite it.",
|
|
7119
|
+
temperature: 0
|
|
7120
|
+
}
|
|
6742
7121
|
);
|
|
6743
7122
|
return rewrite.trim() || question;
|
|
6744
7123
|
}
|
|
@@ -6762,10 +7141,13 @@ ${context}
|
|
|
6762
7141
|
Suggestions:`;
|
|
6763
7142
|
const response = await this.llmProvider.chat(
|
|
6764
7143
|
[
|
|
6765
|
-
{ role: "system", content: "You are a helpful assistant that generates search suggestions." },
|
|
6766
7144
|
{ role: "user", content: prompt }
|
|
6767
7145
|
],
|
|
6768
|
-
""
|
|
7146
|
+
"",
|
|
7147
|
+
{
|
|
7148
|
+
systemPrompt: "You are a helpful assistant that generates search suggestions based on the provided snippets. Focus on questions that can be answered by the context, keep each under 10 words, and return ONLY a JSON array of strings.",
|
|
7149
|
+
temperature: 0
|
|
7150
|
+
}
|
|
6769
7151
|
);
|
|
6770
7152
|
const match = response.match(/\[[\s\S]*\]/);
|
|
6771
7153
|
if (match) {
|
|
@@ -6950,6 +7332,30 @@ var VectorPlugin = class {
|
|
|
6950
7332
|
}
|
|
6951
7333
|
};
|
|
6952
7334
|
|
|
7335
|
+
// src/core/Retrivora.ts
|
|
7336
|
+
var Retrivora = class {
|
|
7337
|
+
constructor(config) {
|
|
7338
|
+
this.config = ConfigResolver.resolveUniversal(config);
|
|
7339
|
+
this.pipeline = new Pipeline(this.config);
|
|
7340
|
+
}
|
|
7341
|
+
async initialize() {
|
|
7342
|
+
await ConfigValidator.validateAndThrow(this.config);
|
|
7343
|
+
await this.pipeline.initialize();
|
|
7344
|
+
}
|
|
7345
|
+
async ingest(documents, namespace) {
|
|
7346
|
+
return this.pipeline.ingest(documents, namespace);
|
|
7347
|
+
}
|
|
7348
|
+
async ask(question, history = [], namespace) {
|
|
7349
|
+
return this.pipeline.ask(question, history, namespace);
|
|
7350
|
+
}
|
|
7351
|
+
askStream(question, history = [], namespace) {
|
|
7352
|
+
return this.pipeline.askStream(question, history, namespace);
|
|
7353
|
+
}
|
|
7354
|
+
getPipeline() {
|
|
7355
|
+
return this.pipeline;
|
|
7356
|
+
}
|
|
7357
|
+
};
|
|
7358
|
+
|
|
6953
7359
|
// src/config/ConfigBuilder.ts
|
|
6954
7360
|
var ConfigBuilder = class {
|
|
6955
7361
|
/**
|
|
@@ -7318,6 +7724,10 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7318
7724
|
if (!isActive) break;
|
|
7319
7725
|
if (typeof chunk === "string") {
|
|
7320
7726
|
enqueue(sseTextFrame(chunk));
|
|
7727
|
+
} else if (chunk && typeof chunk === "object" && "type" in chunk && chunk.type === "thinking") {
|
|
7728
|
+
enqueue(`data: ${JSON.stringify(chunk)}
|
|
7729
|
+
|
|
7730
|
+
`);
|
|
7321
7731
|
} else {
|
|
7322
7732
|
enqueue(sseMetaFrame(chunk));
|
|
7323
7733
|
const responseChunk = chunk;
|
|
@@ -7492,14 +7902,17 @@ function createUploadHandler(configOrPlugin) {
|
|
|
7492
7902
|
// Annotate the CommonJS export names for ESM import in node:
|
|
7493
7903
|
0 && (module.exports = {
|
|
7494
7904
|
AnthropicProvider,
|
|
7905
|
+
AuthenticationException,
|
|
7495
7906
|
BaseVectorProvider,
|
|
7496
7907
|
BatchProcessor,
|
|
7497
7908
|
ChromaDBProvider,
|
|
7498
7909
|
ConfigBuilder,
|
|
7499
7910
|
ConfigResolver,
|
|
7500
7911
|
ConfigValidator,
|
|
7912
|
+
ConfigurationException,
|
|
7501
7913
|
DocumentChunker,
|
|
7502
7914
|
DocumentParser,
|
|
7915
|
+
EmbeddingFailedException,
|
|
7503
7916
|
EmbeddingStrategy,
|
|
7504
7917
|
EmbeddingStrategyResolver,
|
|
7505
7918
|
LLMFactory,
|
|
@@ -7514,9 +7927,14 @@ function createUploadHandler(configOrPlugin) {
|
|
|
7514
7927
|
Pipeline,
|
|
7515
7928
|
PostgreSQLProvider,
|
|
7516
7929
|
ProviderHealthCheck,
|
|
7930
|
+
ProviderNotFoundException,
|
|
7517
7931
|
ProviderRegistry,
|
|
7518
7932
|
QdrantProvider,
|
|
7933
|
+
RateLimitException,
|
|
7519
7934
|
RedisProvider,
|
|
7935
|
+
RetrievalException,
|
|
7936
|
+
Retrivora,
|
|
7937
|
+
RetrivoraError,
|
|
7520
7938
|
UniversalLLMAdapter,
|
|
7521
7939
|
UniversalVectorProvider,
|
|
7522
7940
|
VECTOR_PROFILES,
|