@retrivora-ai/rag-engine 1.9.3 → 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 +552 -198
- package/dist/handlers/index.mjs +552 -198
- 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 +612 -198
- package/dist/server.mjs +604 -198
- 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 +224 -67
- 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 +9 -4
- 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 = [
|
|
@@ -2066,14 +2102,17 @@ var init_SimpleGraphProvider = __esm({
|
|
|
2066
2102
|
var server_exports = {};
|
|
2067
2103
|
__export(server_exports, {
|
|
2068
2104
|
AnthropicProvider: () => AnthropicProvider,
|
|
2105
|
+
AuthenticationException: () => AuthenticationException,
|
|
2069
2106
|
BaseVectorProvider: () => BaseVectorProvider,
|
|
2070
2107
|
BatchProcessor: () => BatchProcessor,
|
|
2071
2108
|
ChromaDBProvider: () => ChromaDBProvider,
|
|
2072
2109
|
ConfigBuilder: () => ConfigBuilder,
|
|
2073
2110
|
ConfigResolver: () => ConfigResolver,
|
|
2074
2111
|
ConfigValidator: () => ConfigValidator,
|
|
2112
|
+
ConfigurationException: () => ConfigurationException,
|
|
2075
2113
|
DocumentChunker: () => DocumentChunker,
|
|
2076
2114
|
DocumentParser: () => DocumentParser,
|
|
2115
|
+
EmbeddingFailedException: () => EmbeddingFailedException,
|
|
2077
2116
|
EmbeddingStrategy: () => EmbeddingStrategy,
|
|
2078
2117
|
EmbeddingStrategyResolver: () => EmbeddingStrategyResolver,
|
|
2079
2118
|
LLMFactory: () => LLMFactory,
|
|
@@ -2088,9 +2127,14 @@ __export(server_exports, {
|
|
|
2088
2127
|
Pipeline: () => Pipeline,
|
|
2089
2128
|
PostgreSQLProvider: () => PostgreSQLProvider,
|
|
2090
2129
|
ProviderHealthCheck: () => ProviderHealthCheck,
|
|
2130
|
+
ProviderNotFoundException: () => ProviderNotFoundException,
|
|
2091
2131
|
ProviderRegistry: () => ProviderRegistry,
|
|
2092
2132
|
QdrantProvider: () => QdrantProvider,
|
|
2133
|
+
RateLimitException: () => RateLimitException,
|
|
2093
2134
|
RedisProvider: () => RedisProvider,
|
|
2135
|
+
RetrievalException: () => RetrievalException,
|
|
2136
|
+
Retrivora: () => Retrivora,
|
|
2137
|
+
RetrivoraError: () => RetrivoraError,
|
|
2094
2138
|
UniversalLLMAdapter: () => UniversalLLMAdapter,
|
|
2095
2139
|
UniversalVectorProvider: () => UniversalVectorProvider,
|
|
2096
2140
|
VECTOR_PROFILES: () => VECTOR_PROFILES,
|
|
@@ -2181,7 +2225,7 @@ function getRagConfig(baseConfig, env = process.env) {
|
|
|
2181
2225
|
return getEnvConfig(env, baseConfig);
|
|
2182
2226
|
}
|
|
2183
2227
|
function getEnvConfig(env = process.env, base) {
|
|
2184
|
-
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;
|
|
2185
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__";
|
|
2186
2230
|
const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
|
|
2187
2231
|
const llmProvider = readEnum(env, "LLM_PROVIDER", "openai", LLM_PROVIDERS);
|
|
@@ -2251,7 +2295,7 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2251
2295
|
rest: "default",
|
|
2252
2296
|
custom: "default"
|
|
2253
2297
|
};
|
|
2254
|
-
return {
|
|
2298
|
+
return __spreadValues({
|
|
2255
2299
|
projectId,
|
|
2256
2300
|
vectorDb: {
|
|
2257
2301
|
provider: vectorProvider,
|
|
@@ -2267,7 +2311,9 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2267
2311
|
maxTokens: readNumber(env, "LLM_MAX_TOKENS", 4096),
|
|
2268
2312
|
temperature: readNumber(env, "LLM_TEMPERATURE", 0.7),
|
|
2269
2313
|
options: {
|
|
2270
|
-
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
|
|
2271
2317
|
}
|
|
2272
2318
|
},
|
|
2273
2319
|
embedding: {
|
|
@@ -2299,11 +2345,76 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2299
2345
|
topK: readNumber(env, "RAG_TOP_K", 5),
|
|
2300
2346
|
scoreThreshold: readNumber(env, "RAG_SCORE_THRESHOLD", 0),
|
|
2301
2347
|
chunkSize: readNumber(env, "RAG_CHUNK_SIZE", 1e3),
|
|
2302
|
-
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
|
+
})()
|
|
2303
2365
|
}
|
|
2304
|
-
}
|
|
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
|
+
} : {});
|
|
2305
2376
|
}
|
|
2306
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
|
+
|
|
2307
2418
|
// src/core/ConfigResolver.ts
|
|
2308
2419
|
var ConfigResolver = class {
|
|
2309
2420
|
/**
|
|
@@ -2330,24 +2441,81 @@ var ConfigResolver = class {
|
|
|
2330
2441
|
rag: hostConfig.rag ? __spreadValues(__spreadValues({}, envConfig.rag), hostConfig.rag) : envConfig.rag
|
|
2331
2442
|
});
|
|
2332
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
|
+
}
|
|
2333
2458
|
/**
|
|
2334
2459
|
* Validates the configuration for required fields.
|
|
2335
2460
|
*/
|
|
2336
2461
|
static validate(config) {
|
|
2337
2462
|
if (!config.projectId) {
|
|
2338
|
-
throw new
|
|
2463
|
+
throw new ConfigurationException("[ConfigResolver] projectId is required");
|
|
2339
2464
|
}
|
|
2340
2465
|
if (!config.vectorDb.provider) {
|
|
2341
|
-
throw new
|
|
2466
|
+
throw new ConfigurationException("[ConfigResolver] vectorDb.provider is required");
|
|
2342
2467
|
}
|
|
2343
2468
|
if (!config.llm.provider) {
|
|
2344
|
-
throw new
|
|
2469
|
+
throw new ConfigurationException("[ConfigResolver] llm.provider is required");
|
|
2345
2470
|
}
|
|
2346
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
|
+
}
|
|
2347
2497
|
};
|
|
2348
2498
|
|
|
2349
2499
|
// src/llm/providers/OpenAIProvider.ts
|
|
2350
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
|
|
2351
2519
|
var OpenAIProvider = class {
|
|
2352
2520
|
constructor(llmConfig, embeddingConfig) {
|
|
2353
2521
|
if (!llmConfig.apiKey) throw new Error("[OpenAIProvider] llmConfig.apiKey is required");
|
|
@@ -2411,16 +2579,10 @@ var OpenAIProvider = class {
|
|
|
2411
2579
|
}
|
|
2412
2580
|
async chat(messages, context, options) {
|
|
2413
2581
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
2414
|
-
const
|
|
2415
|
-
|
|
2416
|
-
Context:
|
|
2417
|
-
${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.";
|
|
2418
2583
|
const systemMessage = {
|
|
2419
2584
|
role: "system",
|
|
2420
|
-
content:
|
|
2421
|
-
|
|
2422
|
-
Context:
|
|
2423
|
-
${context}`
|
|
2585
|
+
content: buildSystemContent(basePrompt, context)
|
|
2424
2586
|
};
|
|
2425
2587
|
const formattedMessages = [
|
|
2426
2588
|
systemMessage,
|
|
@@ -2441,16 +2603,10 @@ ${context}`
|
|
|
2441
2603
|
chatStream(messages, context, options) {
|
|
2442
2604
|
return __asyncGenerator(this, null, function* () {
|
|
2443
2605
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
2444
|
-
const
|
|
2445
|
-
|
|
2446
|
-
Context:
|
|
2447
|
-
${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.";
|
|
2448
2607
|
const systemMessage = {
|
|
2449
2608
|
role: "system",
|
|
2450
|
-
content:
|
|
2451
|
-
|
|
2452
|
-
Context:
|
|
2453
|
-
${context}`
|
|
2609
|
+
content: buildSystemContent(basePrompt, context)
|
|
2454
2610
|
};
|
|
2455
2611
|
const formattedMessages = [
|
|
2456
2612
|
systemMessage,
|
|
@@ -2571,58 +2727,87 @@ var AnthropicProvider = class {
|
|
|
2571
2727
|
};
|
|
2572
2728
|
}
|
|
2573
2729
|
async chat(messages, context, options) {
|
|
2574
|
-
var _a, _b, _c, _d;
|
|
2575
|
-
const
|
|
2576
|
-
|
|
2577
|
-
Context:
|
|
2578
|
-
${context}`;
|
|
2579
|
-
const system = resolvedPrompt.includes("{{context}}") ? resolvedPrompt.replace("{{context}}", context) : (options == null ? void 0 : options.systemPrompt) ? resolvedPrompt : `${resolvedPrompt}
|
|
2580
|
-
|
|
2581
|
-
Context:
|
|
2582
|
-
${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);
|
|
2583
2733
|
const anthropicMessages = messages.map((m) => ({
|
|
2584
2734
|
role: m.role === "assistant" ? "assistant" : "user",
|
|
2585
2735
|
content: m.content
|
|
2586
2736
|
}));
|
|
2587
|
-
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({
|
|
2588
2754
|
model: this.llmConfig.model,
|
|
2589
|
-
max_tokens: (
|
|
2755
|
+
max_tokens: (_k = (_j = options == null ? void 0 : options.maxTokens) != null ? _j : this.llmConfig.maxTokens) != null ? _k : 1024,
|
|
2590
2756
|
system,
|
|
2591
2757
|
messages: anthropicMessages
|
|
2592
|
-
});
|
|
2593
|
-
|
|
2594
|
-
|
|
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;
|
|
2595
2766
|
}
|
|
2596
2767
|
chatStream(messages, context, options) {
|
|
2597
2768
|
return __asyncGenerator(this, null, function* () {
|
|
2598
|
-
var _a, _b, _c, _d;
|
|
2599
|
-
const
|
|
2600
|
-
|
|
2601
|
-
Context:
|
|
2602
|
-
${context}`;
|
|
2603
|
-
const system = resolvedPrompt.includes("{{context}}") ? resolvedPrompt.replace("{{context}}", context) : (options == null ? void 0 : options.systemPrompt) ? resolvedPrompt : `${resolvedPrompt}
|
|
2604
|
-
|
|
2605
|
-
Context:
|
|
2606
|
-
${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);
|
|
2607
2772
|
const anthropicMessages = messages.map((m) => ({
|
|
2608
2773
|
role: m.role === "assistant" ? "assistant" : "user",
|
|
2609
2774
|
content: m.content
|
|
2610
2775
|
}));
|
|
2611
|
-
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({
|
|
2612
2793
|
model: this.llmConfig.model,
|
|
2613
|
-
max_tokens: (
|
|
2794
|
+
max_tokens: (_k = (_j = options == null ? void 0 : options.maxTokens) != null ? _j : this.llmConfig.maxTokens) != null ? _k : 1024,
|
|
2614
2795
|
system,
|
|
2615
2796
|
messages: anthropicMessages,
|
|
2616
2797
|
stream: true
|
|
2617
|
-
}));
|
|
2798
|
+
}, extraParams)));
|
|
2618
2799
|
if (!stream) {
|
|
2619
2800
|
throw new Error("[AnthropicProvider] messages.create stream is undefined");
|
|
2620
2801
|
}
|
|
2621
2802
|
try {
|
|
2622
2803
|
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
2623
2804
|
const chunk = temp.value;
|
|
2624
|
-
if (chunk.type === "content_block_delta"
|
|
2625
|
-
|
|
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
|
+
}
|
|
2626
2811
|
}
|
|
2627
2812
|
}
|
|
2628
2813
|
} catch (temp) {
|
|
@@ -2666,9 +2851,10 @@ ${context}`;
|
|
|
2666
2851
|
var import_axios = __toESM(require("axios"));
|
|
2667
2852
|
var OllamaProvider = class {
|
|
2668
2853
|
constructor(llmConfig, embeddingConfig) {
|
|
2669
|
-
var _a;
|
|
2854
|
+
var _a, _b;
|
|
2670
2855
|
const baseURL = (_a = llmConfig.baseUrl) != null ? _a : "http://localhost:11434";
|
|
2671
|
-
|
|
2856
|
+
const timeout = Number((_b = llmConfig.options) == null ? void 0 : _b.timeout) || 3e5;
|
|
2857
|
+
this.http = import_axios.default.create({ baseURL, timeout });
|
|
2672
2858
|
this.llmConfig = llmConfig;
|
|
2673
2859
|
this.embeddingConfig = embeddingConfig;
|
|
2674
2860
|
}
|
|
@@ -2724,14 +2910,15 @@ var OllamaProvider = class {
|
|
|
2724
2910
|
};
|
|
2725
2911
|
}
|
|
2726
2912
|
async chat(messages, context, options) {
|
|
2727
|
-
var _a, _b, _c, _d;
|
|
2728
|
-
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);
|
|
2729
2916
|
const { data } = await this.http.post("/api/chat", {
|
|
2730
2917
|
model: this.llmConfig.model,
|
|
2731
2918
|
stream: false,
|
|
2732
2919
|
options: {
|
|
2733
|
-
temperature: (
|
|
2734
|
-
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
|
|
2735
2922
|
},
|
|
2736
2923
|
messages: [
|
|
2737
2924
|
{ role: "system", content: system },
|
|
@@ -2742,14 +2929,15 @@ var OllamaProvider = class {
|
|
|
2742
2929
|
}
|
|
2743
2930
|
chatStream(messages, context, options) {
|
|
2744
2931
|
return __asyncGenerator(this, null, function* () {
|
|
2745
|
-
var _a, _b, _c, _d, _e, _f;
|
|
2746
|
-
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);
|
|
2747
2935
|
const response = yield new __await(this.http.post("/api/chat", {
|
|
2748
2936
|
model: this.llmConfig.model,
|
|
2749
2937
|
stream: true,
|
|
2750
2938
|
options: {
|
|
2751
|
-
temperature: (
|
|
2752
|
-
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
|
|
2753
2941
|
},
|
|
2754
2942
|
messages: [
|
|
2755
2943
|
{ role: "system", content: system },
|
|
@@ -2771,7 +2959,7 @@ var OllamaProvider = class {
|
|
|
2771
2959
|
if (!line.trim()) continue;
|
|
2772
2960
|
try {
|
|
2773
2961
|
const json = JSON.parse(line);
|
|
2774
|
-
if ((
|
|
2962
|
+
if ((_g = json.message) == null ? void 0 : _g.content) {
|
|
2775
2963
|
yield json.message.content;
|
|
2776
2964
|
}
|
|
2777
2965
|
if (json.done) return;
|
|
@@ -2793,26 +2981,12 @@ var OllamaProvider = class {
|
|
|
2793
2981
|
if (lineBuffer.trim()) {
|
|
2794
2982
|
try {
|
|
2795
2983
|
const json = JSON.parse(lineBuffer);
|
|
2796
|
-
if ((
|
|
2984
|
+
if ((_h = json.message) == null ? void 0 : _h.content) yield json.message.content;
|
|
2797
2985
|
} catch (e) {
|
|
2798
2986
|
}
|
|
2799
2987
|
}
|
|
2800
2988
|
});
|
|
2801
2989
|
}
|
|
2802
|
-
buildSystemPrompt(context, overridePrompt) {
|
|
2803
|
-
var _a;
|
|
2804
|
-
if (overridePrompt) {
|
|
2805
|
-
return overridePrompt;
|
|
2806
|
-
}
|
|
2807
|
-
const systemPrompt = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Use the provided context to answer the user's question.
|
|
2808
|
-
|
|
2809
|
-
Context:
|
|
2810
|
-
${context}`;
|
|
2811
|
-
return systemPrompt.includes("{{context}}") ? systemPrompt.replace("{{context}}", context) : `${systemPrompt}
|
|
2812
|
-
|
|
2813
|
-
Context:
|
|
2814
|
-
${context}`;
|
|
2815
|
-
}
|
|
2816
2990
|
async embed(text, options) {
|
|
2817
2991
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
2818
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";
|
|
@@ -2959,21 +3133,6 @@ var GeminiProvider = class {
|
|
|
2959
3133
|
var _a, _b;
|
|
2960
3134
|
return sanitizeModel((_b = optionsModel != null ? optionsModel : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _b : DEFAULT_EMBEDDING_MODEL);
|
|
2961
3135
|
}
|
|
2962
|
-
/**
|
|
2963
|
-
* Build the system instruction string, inserting the RAG context either via
|
|
2964
|
-
* the `{{context}}` placeholder or by appending it.
|
|
2965
|
-
*/
|
|
2966
|
-
buildSystemInstruction(context) {
|
|
2967
|
-
var _a;
|
|
2968
|
-
const base = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Answer questions based on the provided context.
|
|
2969
|
-
|
|
2970
|
-
Context:
|
|
2971
|
-
${context}`;
|
|
2972
|
-
return base.includes("{{context}}") ? base.replace("{{context}}", context) : `${base}
|
|
2973
|
-
|
|
2974
|
-
Context:
|
|
2975
|
-
${context}`;
|
|
2976
|
-
}
|
|
2977
3136
|
/**
|
|
2978
3137
|
* Convert ChatMessage[] to the Gemini contents format.
|
|
2979
3138
|
*
|
|
@@ -2992,16 +3151,17 @@ ${context}`;
|
|
|
2992
3151
|
// ILLMProvider — chat
|
|
2993
3152
|
// -------------------------------------------------------------------------
|
|
2994
3153
|
async chat(messages, context, options) {
|
|
2995
|
-
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.";
|
|
2996
3156
|
const model = this.client.getGenerativeModel({
|
|
2997
3157
|
model: this.llmConfig.model,
|
|
2998
|
-
systemInstruction:
|
|
3158
|
+
systemInstruction: buildSystemContent(basePrompt, context)
|
|
2999
3159
|
});
|
|
3000
3160
|
const result = await model.generateContent({
|
|
3001
3161
|
contents: this.buildGeminiContents(messages),
|
|
3002
3162
|
generationConfig: {
|
|
3003
|
-
temperature: (
|
|
3004
|
-
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,
|
|
3005
3165
|
stopSequences: options == null ? void 0 : options.stop
|
|
3006
3166
|
}
|
|
3007
3167
|
});
|
|
@@ -3009,16 +3169,17 @@ ${context}`;
|
|
|
3009
3169
|
}
|
|
3010
3170
|
chatStream(messages, context, options) {
|
|
3011
3171
|
return __asyncGenerator(this, null, function* () {
|
|
3012
|
-
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.";
|
|
3013
3174
|
const model = this.client.getGenerativeModel({
|
|
3014
3175
|
model: this.llmConfig.model,
|
|
3015
|
-
systemInstruction:
|
|
3176
|
+
systemInstruction: buildSystemContent(basePrompt, context)
|
|
3016
3177
|
});
|
|
3017
3178
|
const result = yield new __await(model.generateContentStream({
|
|
3018
3179
|
contents: this.buildGeminiContents(messages),
|
|
3019
3180
|
generationConfig: {
|
|
3020
|
-
temperature: (
|
|
3021
|
-
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,
|
|
3022
3183
|
stopSequences: options == null ? void 0 : options.stop
|
|
3023
3184
|
}
|
|
3024
3185
|
}));
|
|
@@ -3453,7 +3614,9 @@ var LLMFactory = class _LLMFactory {
|
|
|
3453
3614
|
if (llmConfig.baseUrl || ((_b = llmConfig.options) == null ? void 0 : _b.baseUrl)) {
|
|
3454
3615
|
return new UniversalLLMAdapter(llmConfig);
|
|
3455
3616
|
}
|
|
3456
|
-
throw new
|
|
3617
|
+
throw new ProviderNotFoundException(
|
|
3618
|
+
"LLM",
|
|
3619
|
+
String(llmConfig.provider),
|
|
3457
3620
|
`[LLMFactory] Unknown provider "${llmConfig.provider}". Built-in providers: ${_LLMFactory.listProviders().join(", ")}. Register a custom provider with LLMFactory.register().`
|
|
3458
3621
|
);
|
|
3459
3622
|
}
|
|
@@ -3585,7 +3748,7 @@ var ProviderRegistry = class {
|
|
|
3585
3748
|
return UniversalVectorProvider2;
|
|
3586
3749
|
}
|
|
3587
3750
|
default:
|
|
3588
|
-
throw new
|
|
3751
|
+
throw new ProviderNotFoundException("vector", provider);
|
|
3589
3752
|
}
|
|
3590
3753
|
}
|
|
3591
3754
|
static async createVectorProvider(config) {
|
|
@@ -3603,12 +3766,18 @@ var ProviderRegistry = class {
|
|
|
3603
3766
|
return new SimpleGraphProvider2(config);
|
|
3604
3767
|
}
|
|
3605
3768
|
default:
|
|
3606
|
-
throw new
|
|
3769
|
+
throw new ProviderNotFoundException("graph", provider);
|
|
3607
3770
|
}
|
|
3608
3771
|
}
|
|
3609
3772
|
static createLLMProvider(llmConfig, embeddingConfig) {
|
|
3610
3773
|
return LLMFactory.create(llmConfig, embeddingConfig);
|
|
3611
3774
|
}
|
|
3775
|
+
static registerLLMProvider(name, factory) {
|
|
3776
|
+
LLMFactory.register(name, factory);
|
|
3777
|
+
}
|
|
3778
|
+
static createEmbeddingProvider(embeddingConfig) {
|
|
3779
|
+
return LLMFactory.createEmbeddingProvider(embeddingConfig);
|
|
3780
|
+
}
|
|
3612
3781
|
};
|
|
3613
3782
|
ProviderRegistry.vectorProviders = {};
|
|
3614
3783
|
ProviderRegistry.graphProviders = {};
|
|
@@ -3755,8 +3924,8 @@ var ConfigValidator = class {
|
|
|
3755
3924
|
const errorItems = errors.filter((e) => e.severity === "error");
|
|
3756
3925
|
if (errorItems.length > 0) {
|
|
3757
3926
|
const message = errorItems.map((e) => `${e.field}: ${e.message}${e.suggestion ? ` (${e.suggestion})` : ""}`).join("\n ");
|
|
3758
|
-
throw new
|
|
3759
|
-
${message}
|
|
3927
|
+
throw new ConfigurationException(`[ConfigValidator] Configuration validation failed:
|
|
3928
|
+
${message}`, errorItems);
|
|
3760
3929
|
}
|
|
3761
3930
|
}
|
|
3762
3931
|
};
|
|
@@ -3943,20 +4112,17 @@ var Reranker = class {
|
|
|
3943
4112
|
}
|
|
3944
4113
|
try {
|
|
3945
4114
|
const topN = matches.slice(0, 10);
|
|
3946
|
-
const
|
|
3947
|
-
|
|
3948
|
-
Return the result as a comma-separated list of document indices in order of relevance, from most relevant to least relevant.
|
|
3949
|
-
Use the indices provided in brackets like [0], [1], etc.
|
|
3950
|
-
Only return the indices (e.g., "2,0,1"), nothing else. Do not include brackets in the output.
|
|
3951
|
-
|
|
3952
|
-
Query: "${query}"
|
|
4115
|
+
const response = await llm.chat(
|
|
4116
|
+
[{ role: "user", content: `Query: "${query}"
|
|
3953
4117
|
|
|
3954
4118
|
Documents:
|
|
3955
|
-
${topN.map((m, i) => `[${i}] ${m.content.replace(/\n/g, " ")}`).join("\n")}
|
|
3956
|
-
const response = await llm.chat(
|
|
3957
|
-
[{ role: "user", content: prompt }],
|
|
4119
|
+
${topN.map((m, i) => `[${i}] ${m.content.replace(/\n/g, " ")}`).join("\n")}` }],
|
|
3958
4120
|
"",
|
|
3959
|
-
{
|
|
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
|
+
}
|
|
3960
4126
|
);
|
|
3961
4127
|
const cleanedResponse = response.trim().replace(/[\[\]\s]/g, "");
|
|
3962
4128
|
const rankedIndices = cleanedResponse.split(",").map(Number).filter((n) => !isNaN(n));
|
|
@@ -4468,6 +4634,18 @@ var QueryProcessor = class {
|
|
|
4468
4634
|
}, normalizedField ? { field: normalizedField } : {}));
|
|
4469
4635
|
}
|
|
4470
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
|
+
};
|
|
4471
4649
|
for (const match of question.matchAll(/["']([^"']{2,100})["']/g)) {
|
|
4472
4650
|
addHint(match[1]);
|
|
4473
4651
|
}
|
|
@@ -4492,7 +4670,13 @@ var QueryProcessor = class {
|
|
|
4492
4670
|
const field = match[1];
|
|
4493
4671
|
const value = match[2];
|
|
4494
4672
|
if (field && !this.isLikelyPromptPhrase(field)) {
|
|
4495
|
-
|
|
4673
|
+
const resolvedField = resolveValidField(field);
|
|
4674
|
+
if (resolvedField) {
|
|
4675
|
+
addHint(value, resolvedField);
|
|
4676
|
+
} else {
|
|
4677
|
+
addHint(value);
|
|
4678
|
+
addHint(field);
|
|
4679
|
+
}
|
|
4496
4680
|
}
|
|
4497
4681
|
}
|
|
4498
4682
|
if (validFields.length > 0) {
|
|
@@ -4538,12 +4722,16 @@ var QueryProcessor = class {
|
|
|
4538
4722
|
];
|
|
4539
4723
|
for (const pattern of fieldValuePatterns) {
|
|
4540
4724
|
for (const match of question.matchAll(pattern)) {
|
|
4541
|
-
const field =
|
|
4725
|
+
const field = (_c = match[1]) != null ? _c : "";
|
|
4542
4726
|
const value = (_d = match[2]) != null ? _d : "";
|
|
4543
|
-
|
|
4544
|
-
|
|
4727
|
+
const resolvedField = resolveValidField(field);
|
|
4728
|
+
if (resolvedField) {
|
|
4729
|
+
addHint(value, resolvedField);
|
|
4545
4730
|
} else {
|
|
4546
4731
|
addHint(value);
|
|
4732
|
+
if (field && !this.isLikelyPromptPhrase(field)) {
|
|
4733
|
+
addHint(field);
|
|
4734
|
+
}
|
|
4547
4735
|
}
|
|
4548
4736
|
}
|
|
4549
4737
|
}
|
|
@@ -4770,7 +4958,7 @@ var LLMRouter = class {
|
|
|
4770
4958
|
|
|
4771
4959
|
// src/utils/UITransformer.ts
|
|
4772
4960
|
init_synonyms();
|
|
4773
|
-
var UITransformer = class {
|
|
4961
|
+
var UITransformer = class _UITransformer {
|
|
4774
4962
|
// ─── Public Entry Points ─────────────────────────────────────────────────
|
|
4775
4963
|
/**
|
|
4776
4964
|
* Heuristic-only transform (no LLM required).
|
|
@@ -4832,7 +5020,7 @@ var UITransformer = class {
|
|
|
4832
5020
|
static async analyzeAndDecide(query, sources, llm) {
|
|
4833
5021
|
let intent;
|
|
4834
5022
|
try {
|
|
4835
|
-
intent = await this.detectIntent(query, llm);
|
|
5023
|
+
intent = await this.detectIntent(query, llm, sources);
|
|
4836
5024
|
console.debug("[UITransformer] Detected intent:", intent);
|
|
4837
5025
|
} catch (err) {
|
|
4838
5026
|
console.warn("[UITransformer] Intent detection failed; using heuristic.", err);
|
|
@@ -4850,11 +5038,23 @@ var UITransformer = class {
|
|
|
4850
5038
|
try {
|
|
4851
5039
|
const context = this.buildContextSummary(sources);
|
|
4852
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
|
+
`;
|
|
4853
5050
|
const userPrompt = [
|
|
4854
5051
|
`USER QUESTION: ${query}`,
|
|
4855
5052
|
"",
|
|
4856
5053
|
`DETECTED INTENT (JSON): ${JSON.stringify(intent)}`,
|
|
4857
5054
|
"",
|
|
5055
|
+
`RETRIEVED DATA SCHEMA:`,
|
|
5056
|
+
schemaContext,
|
|
5057
|
+
"",
|
|
4858
5058
|
"RETRIEVED DATA (JSON):",
|
|
4859
5059
|
context
|
|
4860
5060
|
].join("\n");
|
|
@@ -4865,6 +5065,20 @@ var UITransformer = class {
|
|
|
4865
5065
|
);
|
|
4866
5066
|
const parsed = this.parseTransformationResponse(rawResponse);
|
|
4867
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
|
+
}
|
|
4868
5082
|
const intentAllowsTable = intent.wantsExplicitTable || ["tabular", "table", "geographic"].includes(intent.visualizationHint);
|
|
4869
5083
|
const intentWantsPieLikeChart = ["pie_chart", "donut_chart"].includes(intent.recommendedChart) || ["composition", "category_breakdown"].includes(intent.visualizationHint);
|
|
4870
5084
|
if (parsed.type === "table" && !intentAllowsTable) {
|
|
@@ -4894,7 +5108,26 @@ var UITransformer = class {
|
|
|
4894
5108
|
* - The intent object can be reused across both the heuristic and LLM paths.
|
|
4895
5109
|
* - It is easy to unit-test intent detection in isolation.
|
|
4896
5110
|
*/
|
|
4897
|
-
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
|
+
}
|
|
4898
5131
|
const systemPrompt = `You are an intent classifier for a product-search RAG system.
|
|
4899
5132
|
Given a user query, return ONLY a valid JSON object with this exact shape \u2014 no prose, no markdown:
|
|
4900
5133
|
|
|
@@ -4930,8 +5163,11 @@ RULES:
|
|
|
4930
5163
|
- isTemporal: true if time words appear (trend, historical, over time, last year, monthly, etc.)
|
|
4931
5164
|
- isComparison: true if user compares, ranks, or contrasts entities or categories.
|
|
4932
5165
|
- language: detect from the query text itself; default "en" if uncertain.`;
|
|
5166
|
+
const userPrompt = `QUERY: ${query}${schemaProfileText ? `
|
|
5167
|
+
|
|
5168
|
+
${schemaProfileText}` : ""}`;
|
|
4933
5169
|
const rawResponse = await llm.chat(
|
|
4934
|
-
[{ role: "user", content:
|
|
5170
|
+
[{ role: "user", content: userPrompt }],
|
|
4935
5171
|
"",
|
|
4936
5172
|
{ systemPrompt, temperature: 0 }
|
|
4937
5173
|
);
|
|
@@ -5374,10 +5610,21 @@ RULES:
|
|
|
5374
5610
|
const hasEntityTerms = /\b(organization|organisations?|organizations?|company|companies|employee|employees|staff|headcount|workforce)\b/.test(q);
|
|
5375
5611
|
return asksForRecords && (hasNumericPredicate || hasEntityTerms);
|
|
5376
5612
|
}
|
|
5613
|
+
/** @internal kept private for transform() internal logic */
|
|
5377
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) {
|
|
5378
5625
|
const q = query.toLowerCase();
|
|
5379
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);
|
|
5380
|
-
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);
|
|
5381
5628
|
const nonProductEntityTerms = /\b(organization|organisations?|organizations?|company|companies|employee|employees|staff|headcount|workforce)\b/.test(q);
|
|
5382
5629
|
return productTerms && productAction && !nonProductEntityTerms;
|
|
5383
5630
|
}
|
|
@@ -6150,23 +6397,19 @@ function estimateCostUsd(promptTokens, completionTokens, model) {
|
|
|
6150
6397
|
async function scoreHallucination(llm, answer, context) {
|
|
6151
6398
|
const maxContextChars = 3e3;
|
|
6152
6399
|
const truncatedContext = context.length > maxContextChars ? context.slice(0, maxContextChars) + "\n...[truncated]" : context;
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
CONTEXT:
|
|
6400
|
+
try {
|
|
6401
|
+
const raw = await llm.chat(
|
|
6402
|
+
[{ role: "user", content: `CONTEXT:
|
|
6156
6403
|
${truncatedContext}
|
|
6157
6404
|
|
|
6158
6405
|
ANSWER:
|
|
6159
|
-
${answer}
|
|
6160
|
-
|
|
6161
|
-
Return ONLY a valid JSON object with no markdown fences:
|
|
6162
|
-
{"score": <float 0-1>, "reason": "<one sentence>"}
|
|
6163
|
-
|
|
6164
|
-
Where score 0 = fully grounded in context, score 1 = likely hallucinated or unsupported.`;
|
|
6165
|
-
try {
|
|
6166
|
-
const raw = await llm.chat(
|
|
6167
|
-
[{ role: "user", content: prompt }],
|
|
6406
|
+
${answer}` }],
|
|
6168
6407
|
"",
|
|
6169
|
-
{
|
|
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
|
+
}
|
|
6170
6413
|
);
|
|
6171
6414
|
const jsonMatch = raw.match(/\{[\s\S]*\}/);
|
|
6172
6415
|
if (!jsonMatch) return void 0;
|
|
@@ -6226,7 +6469,10 @@ var Pipeline = class {
|
|
|
6226
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.
|
|
6227
6470
|
- Do NOT try to format product lists as tables.
|
|
6228
6471
|
`;
|
|
6229
|
-
this.config.llm.systemPrompt
|
|
6472
|
+
const userPromptPrefix = this.config.llm.systemPrompt ? `${this.config.llm.systemPrompt}
|
|
6473
|
+
|
|
6474
|
+
` : "";
|
|
6475
|
+
this.config.llm.systemPrompt = `${userPromptPrefix}${chartInstruction}`;
|
|
6230
6476
|
this.vectorDB = await ProviderRegistry.createVectorProvider(this.config.vectorDb);
|
|
6231
6477
|
this.llmRouter = new LLMRouter(this.config);
|
|
6232
6478
|
const { llmProvider: resolvedLLM, embeddingProvider } = await EmbeddingStrategyResolver.resolve(
|
|
@@ -6404,11 +6650,11 @@ var Pipeline = class {
|
|
|
6404
6650
|
*/
|
|
6405
6651
|
askStream(_0) {
|
|
6406
6652
|
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
6407
|
-
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;
|
|
6408
6654
|
yield new __await(this.initialize());
|
|
6409
6655
|
const ns = namespace != null ? namespace : this.config.projectId;
|
|
6410
6656
|
const topK = (_b = (_a = this.config.rag) == null ? void 0 : _a.topK) != null ? _b : 5;
|
|
6411
|
-
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;
|
|
6412
6658
|
const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
6413
6659
|
const requestStart = performance.now();
|
|
6414
6660
|
try {
|
|
@@ -6427,12 +6673,13 @@ var Pipeline = class {
|
|
|
6427
6673
|
const embedStart = performance.now();
|
|
6428
6674
|
const cacheKey = `${ns}::${searchQuery}`;
|
|
6429
6675
|
const cachedVector = this.embeddingCache.get(cacheKey);
|
|
6676
|
+
const useGraph = this.graphDB && ((_h = this.config.rag) == null ? void 0 : _h.useGraphRetrieval);
|
|
6430
6677
|
const [strategyResult, embeddedVector] = yield new __await(Promise.all([
|
|
6431
6678
|
QueryProcessor.determineRetrievalStrategy(
|
|
6432
6679
|
searchQuery,
|
|
6433
|
-
this.llmRouter.get("fast"),
|
|
6434
|
-
(
|
|
6435
|
-
(
|
|
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
|
|
6436
6683
|
),
|
|
6437
6684
|
// Embed immediately regardless of strategy — costs nothing if cached.
|
|
6438
6685
|
// If strategy turns out to be 'graph'-only we just won't use the vector.
|
|
@@ -6442,7 +6689,7 @@ var Pipeline = class {
|
|
|
6442
6689
|
if (!cachedVector && queryVector.length > 0) {
|
|
6443
6690
|
this.embeddingCache.set(cacheKey, queryVector);
|
|
6444
6691
|
}
|
|
6445
|
-
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;
|
|
6446
6693
|
const hasMetadataFilter = filter.metadata && Object.keys(filter.metadata).length > 0;
|
|
6447
6694
|
const hasNumericPredicates = Array.isArray(filter.__numericPredicates) && filter.__numericPredicates.length > 0;
|
|
6448
6695
|
const wantsExhaustiveList = hasNumericPredicates || hasMetadataFilter || /\b(list|all|show|provide|give|get|browse|find|search|display)\b/i.test(question);
|
|
@@ -6455,7 +6702,7 @@ var Pipeline = class {
|
|
|
6455
6702
|
const structuredSources = this.applyStructuredFilters(rawSources, filter);
|
|
6456
6703
|
let fullSources = hasNumericPredicates ? structuredSources : structuredSources.filter((m) => m.score >= scoreThreshold);
|
|
6457
6704
|
const rerankLimit = wantsExhaustiveList ? retrievalLimit : topK;
|
|
6458
|
-
if (!hasNumericPredicates && ((
|
|
6705
|
+
if (!hasNumericPredicates && ((_l = this.config.rag) == null ? void 0 : _l.useReranking)) {
|
|
6459
6706
|
fullSources = yield new __await(this.reranker.rerank(fullSources, question, rerankLimit));
|
|
6460
6707
|
} else if (!wantsExhaustiveList) {
|
|
6461
6708
|
fullSources = fullSources.slice(0, topK);
|
|
@@ -6486,34 +6733,117 @@ VECTOR CONTEXT:
|
|
|
6486
6733
|
${context}`;
|
|
6487
6734
|
}
|
|
6488
6735
|
const allMetadataKeys = Array.from(new Set(sources.flatMap((s) => Object.keys(s.metadata || {}))));
|
|
6489
|
-
const
|
|
6490
|
-
|
|
6491
|
-
(
|
|
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(
|
|
6492
6744
|
question,
|
|
6493
6745
|
sources,
|
|
6494
|
-
|
|
6495
|
-
|
|
6746
|
+
this.config,
|
|
6747
|
+
cachedSchema,
|
|
6748
|
+
{ visualizationHint: "product_browse", recommendedChart: "text", filterInStockOnly: false, wantsExplicitTable: false, isTemporal: false, isComparison: false, language: "en" }
|
|
6496
6749
|
)
|
|
6750
|
+
) : this.generateUiTransformation(
|
|
6751
|
+
question,
|
|
6752
|
+
sources,
|
|
6753
|
+
cachedSchema,
|
|
6754
|
+
hasNumericPredicates
|
|
6497
6755
|
).catch((uiError) => {
|
|
6498
6756
|
console.warn("[Pipeline] UI transformation failed concurrently:", uiError);
|
|
6499
|
-
return UITransformer.transform(question, sources, this.config);
|
|
6757
|
+
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6500
6758
|
});
|
|
6759
|
+
let hallucinationScoringPromise = Promise.resolve(void 0);
|
|
6501
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
|
+
}
|
|
6502
6770
|
const hardenedHistory = [...history];
|
|
6503
|
-
const userQuestion = { role: "user", content: question +
|
|
6771
|
+
const userQuestion = { role: "user", content: question + finalRestrictionSuffix };
|
|
6504
6772
|
const messages = [...hardenedHistory, userQuestion];
|
|
6505
|
-
const systemPrompt = (
|
|
6773
|
+
const systemPrompt = (_s = this.config.llm.systemPrompt) != null ? _s : "";
|
|
6506
6774
|
const userPrompt = messages.map((m) => `${m.role}: ${m.content}`).join("\n");
|
|
6507
6775
|
let fullReply = "";
|
|
6776
|
+
let thinkingText = "";
|
|
6777
|
+
let thinkingStartMs = performance.now();
|
|
6778
|
+
let thinkingDurationMs = 0;
|
|
6508
6779
|
const generateStart = performance.now();
|
|
6509
6780
|
if (this.llmProvider.chatStream) {
|
|
6510
6781
|
const stream = this.llmProvider.chatStream(messages, context);
|
|
6511
6782
|
if (!stream) throw new Error(`[Pipeline] ${this.config.llm.provider} chatStream returned undefined`);
|
|
6783
|
+
let inThinking = false;
|
|
6784
|
+
let textBuffer = "";
|
|
6512
6785
|
try {
|
|
6513
6786
|
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
6514
6787
|
const chunk = temp.value;
|
|
6515
|
-
|
|
6516
|
-
|
|
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
|
+
}
|
|
6517
6847
|
}
|
|
6518
6848
|
} catch (temp) {
|
|
6519
6849
|
error = [temp];
|
|
@@ -6525,17 +6855,42 @@ ${context}`;
|
|
|
6525
6855
|
throw error[0];
|
|
6526
6856
|
}
|
|
6527
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
|
+
}
|
|
6528
6867
|
} else {
|
|
6529
6868
|
const reply = yield new __await(this.llmProvider.chat(messages, context));
|
|
6530
|
-
|
|
6531
|
-
|
|
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);
|
|
6532
6887
|
}
|
|
6533
6888
|
const generateMs = performance.now() - generateStart;
|
|
6534
6889
|
const totalMs = performance.now() - requestStart;
|
|
6535
6890
|
const latency = {
|
|
6536
6891
|
embedMs: Math.round(embedMs),
|
|
6537
6892
|
retrieveMs: Math.round(retrieveMs),
|
|
6538
|
-
rerankMs: ((
|
|
6893
|
+
rerankMs: ((_v = this.config.rag) == null ? void 0 : _v.useReranking) ? Math.round(rerankMs) : void 0,
|
|
6539
6894
|
generateMs: Math.round(generateMs),
|
|
6540
6895
|
totalMs: Math.round(totalMs)
|
|
6541
6896
|
};
|
|
@@ -6548,12 +6903,16 @@ ${context}`;
|
|
|
6548
6903
|
totalTokens: promptTokens + completionTokens,
|
|
6549
6904
|
estimatedCostUsd: estimateCostUsd(promptTokens, completionTokens, this.config.llm.model)
|
|
6550
6905
|
};
|
|
6551
|
-
const
|
|
6906
|
+
const [uiTransformation, hallucinationResult] = yield new __await(Promise.all([
|
|
6907
|
+
uiTransformationPromise,
|
|
6908
|
+
hallucinationScoringPromise
|
|
6909
|
+
]));
|
|
6910
|
+
const trace = __spreadValues({
|
|
6552
6911
|
requestId,
|
|
6553
6912
|
query: question,
|
|
6554
6913
|
rewrittenQuery,
|
|
6555
6914
|
systemPrompt,
|
|
6556
|
-
userPrompt: question +
|
|
6915
|
+
userPrompt: question + finalRestrictionSuffix,
|
|
6557
6916
|
chunks: sources.map((s) => {
|
|
6558
6917
|
var _a2;
|
|
6559
6918
|
return {
|
|
@@ -6567,22 +6926,19 @@ ${context}`;
|
|
|
6567
6926
|
latency,
|
|
6568
6927
|
tokens,
|
|
6569
6928
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6570
|
-
}
|
|
6571
|
-
|
|
6929
|
+
}, hallucinationResult ? {
|
|
6930
|
+
hallucinationScore: hallucinationResult.score,
|
|
6931
|
+
hallucinationReason: hallucinationResult.reason
|
|
6932
|
+
} : {});
|
|
6572
6933
|
yield {
|
|
6573
6934
|
reply: "",
|
|
6574
6935
|
sources,
|
|
6575
6936
|
graphData,
|
|
6576
6937
|
ui_transformation: uiTransformation,
|
|
6577
|
-
trace
|
|
6938
|
+
trace,
|
|
6939
|
+
thinking: thinkingText || void 0,
|
|
6940
|
+
thinkingMs: thinkingDurationMs > 0 ? Math.round(thinkingDurationMs) : void 0
|
|
6578
6941
|
};
|
|
6579
|
-
scoreHallucination(this.llmProvider, fullReply, context).then((hallucinationResult) => {
|
|
6580
|
-
if (hallucinationResult) {
|
|
6581
|
-
trace.hallucinationScore = hallucinationResult.score;
|
|
6582
|
-
trace.hallucinationReason = hallucinationResult.reason;
|
|
6583
|
-
}
|
|
6584
|
-
}).catch(() => {
|
|
6585
|
-
});
|
|
6586
6942
|
} catch (error2) {
|
|
6587
6943
|
throw new Error(`[Pipeline] Stream failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
6588
6944
|
}
|
|
@@ -6592,18 +6948,30 @@ ${context}`;
|
|
|
6592
6948
|
* Universal retrieval method combining all enabled providers.
|
|
6593
6949
|
* Uses an LRU-bounded embedding cache to avoid re-embedding the same query.
|
|
6594
6950
|
*/
|
|
6595
|
-
async generateUiTransformation(question, sources,
|
|
6951
|
+
async generateUiTransformation(question, sources, cachedSchema, forceDeterministic = false) {
|
|
6952
|
+
var _a;
|
|
6596
6953
|
if (!sources || sources.length === 0) {
|
|
6597
|
-
return UITransformer.transform(question, sources, this.config,
|
|
6954
|
+
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6598
6955
|
}
|
|
6599
|
-
if (
|
|
6600
|
-
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);
|
|
6601
6969
|
}
|
|
6602
6970
|
try {
|
|
6603
6971
|
return await UITransformer.analyzeAndDecide(question, sources, this.llmRouter.get("fast"));
|
|
6604
6972
|
} catch (err) {
|
|
6605
6973
|
console.warn("[Pipeline] generateUiTransformation failed, using heuristic fallback:", err);
|
|
6606
|
-
return UITransformer.transform(question, sources, this.config,
|
|
6974
|
+
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6607
6975
|
}
|
|
6608
6976
|
}
|
|
6609
6977
|
applyStructuredFilters(sources, filter) {
|
|
@@ -6687,25 +7055,29 @@ ${context}`;
|
|
|
6687
7055
|
return Number.isFinite(numeric) ? numeric : null;
|
|
6688
7056
|
}
|
|
6689
7057
|
async retrieve(query, options) {
|
|
6690
|
-
var _a, _b, _c, _d, _e, _f;
|
|
7058
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
6691
7059
|
const ns = (_a = options.namespace) != null ? _a : this.config.projectId;
|
|
6692
7060
|
const topK = (_b = options.topK) != null ? _b : 5;
|
|
6693
7061
|
const cacheKey = `${ns}::${query}`;
|
|
6694
7062
|
let queryVector = this.embeddingCache.get(cacheKey);
|
|
6695
|
-
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
|
+
);
|
|
6696
7068
|
console.debug(`[Pipeline] Determined retrieval strategy: ${strategy}`);
|
|
6697
7069
|
const [retrievedVector, graphData] = await Promise.all([
|
|
6698
7070
|
// Only embed if we need vector search (strategy is 'vector' or 'both')
|
|
6699
7071
|
strategy === "vector" || strategy === "both" ? queryVector ? Promise.resolve(queryVector) : this.embeddingProvider.embed(query, { taskType: "query" }) : Promise.resolve([]),
|
|
6700
7072
|
// Only query graph if we need graph search (strategy is 'graph' or 'both')
|
|
6701
|
-
(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)
|
|
6702
7074
|
]);
|
|
6703
7075
|
if ((strategy === "vector" || strategy === "both") && !queryVector && retrievedVector && retrievedVector.length > 0) {
|
|
6704
7076
|
this.embeddingCache.set(cacheKey, retrievedVector);
|
|
6705
7077
|
queryVector = retrievedVector;
|
|
6706
7078
|
}
|
|
6707
|
-
const baseFilter = __spreadProps(__spreadValues({}, (
|
|
6708
|
-
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);
|
|
6709
7081
|
if (numericPredicates.length > 0) {
|
|
6710
7082
|
baseFilter.__numericPredicates = numericPredicates;
|
|
6711
7083
|
}
|
|
@@ -6716,7 +7088,7 @@ ${context}`;
|
|
|
6716
7088
|
) : [];
|
|
6717
7089
|
const resolvedSources = [];
|
|
6718
7090
|
for (const source of sources) {
|
|
6719
|
-
const parentId = (
|
|
7091
|
+
const parentId = (_g = source.metadata) == null ? void 0 : _g.parent_id;
|
|
6720
7092
|
if (parentId) {
|
|
6721
7093
|
console.log(`[Pipeline] Multi-Vector: Found child chunk. Parent ID: ${parentId}`);
|
|
6722
7094
|
resolvedSources.push(source);
|
|
@@ -6739,10 +7111,13 @@ New Question: ${question}
|
|
|
6739
7111
|
Optimized Search Query:`;
|
|
6740
7112
|
const rewrite = await this.llmProvider.chat(
|
|
6741
7113
|
[
|
|
6742
|
-
{ role: "system", content: "You are an assistant that optimizes search queries for RAG systems." },
|
|
6743
7114
|
{ role: "user", content: prompt }
|
|
6744
7115
|
],
|
|
6745
|
-
""
|
|
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
|
+
}
|
|
6746
7121
|
);
|
|
6747
7122
|
return rewrite.trim() || question;
|
|
6748
7123
|
}
|
|
@@ -6766,10 +7141,13 @@ ${context}
|
|
|
6766
7141
|
Suggestions:`;
|
|
6767
7142
|
const response = await this.llmProvider.chat(
|
|
6768
7143
|
[
|
|
6769
|
-
{ role: "system", content: "You are a helpful assistant that generates search suggestions." },
|
|
6770
7144
|
{ role: "user", content: prompt }
|
|
6771
7145
|
],
|
|
6772
|
-
""
|
|
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
|
+
}
|
|
6773
7151
|
);
|
|
6774
7152
|
const match = response.match(/\[[\s\S]*\]/);
|
|
6775
7153
|
if (match) {
|
|
@@ -6954,6 +7332,30 @@ var VectorPlugin = class {
|
|
|
6954
7332
|
}
|
|
6955
7333
|
};
|
|
6956
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
|
+
|
|
6957
7359
|
// src/config/ConfigBuilder.ts
|
|
6958
7360
|
var ConfigBuilder = class {
|
|
6959
7361
|
/**
|
|
@@ -7322,6 +7724,10 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7322
7724
|
if (!isActive) break;
|
|
7323
7725
|
if (typeof chunk === "string") {
|
|
7324
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
|
+
`);
|
|
7325
7731
|
} else {
|
|
7326
7732
|
enqueue(sseMetaFrame(chunk));
|
|
7327
7733
|
const responseChunk = chunk;
|
|
@@ -7496,14 +7902,17 @@ function createUploadHandler(configOrPlugin) {
|
|
|
7496
7902
|
// Annotate the CommonJS export names for ESM import in node:
|
|
7497
7903
|
0 && (module.exports = {
|
|
7498
7904
|
AnthropicProvider,
|
|
7905
|
+
AuthenticationException,
|
|
7499
7906
|
BaseVectorProvider,
|
|
7500
7907
|
BatchProcessor,
|
|
7501
7908
|
ChromaDBProvider,
|
|
7502
7909
|
ConfigBuilder,
|
|
7503
7910
|
ConfigResolver,
|
|
7504
7911
|
ConfigValidator,
|
|
7912
|
+
ConfigurationException,
|
|
7505
7913
|
DocumentChunker,
|
|
7506
7914
|
DocumentParser,
|
|
7915
|
+
EmbeddingFailedException,
|
|
7507
7916
|
EmbeddingStrategy,
|
|
7508
7917
|
EmbeddingStrategyResolver,
|
|
7509
7918
|
LLMFactory,
|
|
@@ -7518,9 +7927,14 @@ function createUploadHandler(configOrPlugin) {
|
|
|
7518
7927
|
Pipeline,
|
|
7519
7928
|
PostgreSQLProvider,
|
|
7520
7929
|
ProviderHealthCheck,
|
|
7930
|
+
ProviderNotFoundException,
|
|
7521
7931
|
ProviderRegistry,
|
|
7522
7932
|
QdrantProvider,
|
|
7933
|
+
RateLimitException,
|
|
7523
7934
|
RedisProvider,
|
|
7935
|
+
RetrievalException,
|
|
7936
|
+
Retrivora,
|
|
7937
|
+
RetrivoraError,
|
|
7524
7938
|
UniversalLLMAdapter,
|
|
7525
7939
|
UniversalVectorProvider,
|
|
7526
7940
|
VECTOR_PROFILES,
|