@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.mjs
CHANGED
|
@@ -640,6 +640,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
640
640
|
CREATE INDEX IF NOT EXISTS ${this.uploadTable}_embedding_idx
|
|
641
641
|
ON ${this.uploadTable}
|
|
642
642
|
USING hnsw (embedding vector_cosine_ops)
|
|
643
|
+
`);
|
|
644
|
+
await client.query(`
|
|
645
|
+
CREATE INDEX IF NOT EXISTS "${this.uploadTable}_fts_idx"
|
|
646
|
+
ON "${this.uploadTable}"
|
|
647
|
+
USING gin (to_tsvector('english', content))
|
|
643
648
|
`);
|
|
644
649
|
const res = await client.query(`
|
|
645
650
|
SELECT table_name
|
|
@@ -710,6 +715,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
710
715
|
CREATE INDEX IF NOT EXISTS "${tableName}_embedding_idx"
|
|
711
716
|
ON "${tableName}"
|
|
712
717
|
USING hnsw (embedding vector_cosine_ops)
|
|
718
|
+
`);
|
|
719
|
+
await client.query(`
|
|
720
|
+
CREATE INDEX IF NOT EXISTS "${tableName}_fts_idx"
|
|
721
|
+
ON "${tableName}"
|
|
722
|
+
USING gin (to_tsvector('english', content))
|
|
713
723
|
`);
|
|
714
724
|
if (!this.tables.includes(tableName)) {
|
|
715
725
|
this.tables.push(tableName);
|
|
@@ -801,8 +811,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
801
811
|
const paramIdx = baseOffset + filterParams.length;
|
|
802
812
|
const synonyms = (_a3 = FIELD_SYNONYMS[key]) != null ? _a3 : [];
|
|
803
813
|
const keysToCheck = [key, ...synonyms];
|
|
804
|
-
const coalesceExprs = keysToCheck.
|
|
805
|
-
|
|
814
|
+
const coalesceExprs = keysToCheck.flatMap((k) => [
|
|
815
|
+
`metadata->>'${k}'`,
|
|
816
|
+
`to_jsonb(t)->>'${k}'`
|
|
817
|
+
]);
|
|
818
|
+
return `COALESCE(${coalesceExprs.map((expr) => `LOWER(${expr})`).join(", ")}) = LOWER($${paramIdx})`;
|
|
806
819
|
});
|
|
807
820
|
whereClause = `WHERE ${conditions.join(" AND ")}`;
|
|
808
821
|
}
|
|
@@ -813,16 +826,35 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
813
826
|
CASE WHEN LOWER(val) IN (${entityHints.map((h) => `'${h.replace(/'/g, "''")}'`).join(", ")})
|
|
814
827
|
THEN 1.0 ELSE 0.0 END
|
|
815
828
|
), 0)
|
|
816
|
-
FROM jsonb_each_text(
|
|
829
|
+
FROM jsonb_each_text(COALESCE(v.metadata, k.metadata)) AS kv(key, val)
|
|
817
830
|
WHERE key IN (${this.searchFields.map((f) => `'${f}'`).join(", ")})
|
|
818
831
|
) * 3.0` : "";
|
|
819
832
|
sqlQuery = `
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
833
|
+
WITH vector_search AS (
|
|
834
|
+
SELECT *, (1 - (embedding <=> $1::vector)) AS vector_score
|
|
835
|
+
FROM "${table}" t
|
|
836
|
+
${whereClause}
|
|
837
|
+
ORDER BY embedding <=> $1::vector ASC
|
|
838
|
+
LIMIT ${tableLimit}
|
|
839
|
+
),
|
|
840
|
+
keyword_search AS (
|
|
841
|
+
SELECT *, COALESCE(ts_rank(to_tsvector('english', content), to_tsquery('english', $2)), 0) AS keyword_score
|
|
842
|
+
FROM "${table}" t
|
|
843
|
+
WHERE ${whereClause ? whereClause.replace("WHERE", "") : "TRUE"}
|
|
844
|
+
AND to_tsvector('english', content) @@ to_tsquery('english', $2)
|
|
845
|
+
ORDER BY keyword_score DESC
|
|
846
|
+
LIMIT ${tableLimit}
|
|
847
|
+
)
|
|
848
|
+
SELECT
|
|
849
|
+
COALESCE(v.id, k.id) AS id,
|
|
850
|
+
COALESCE(v.namespace, k.namespace) AS namespace,
|
|
851
|
+
COALESCE(v.content, k.content) AS content,
|
|
852
|
+
COALESCE(v.metadata, k.metadata) AS metadata,
|
|
853
|
+
COALESCE(v.vector_score, 0) AS vector_score,
|
|
854
|
+
COALESCE(k.keyword_score, 0) AS keyword_score,
|
|
855
|
+
(COALESCE(v.vector_score, 0) + COALESCE(k.keyword_score, 0) * 2.0 ${exactNameScoreExpr}) AS hybrid_score
|
|
856
|
+
FROM vector_search v
|
|
857
|
+
FULL OUTER JOIN keyword_search k ON v.id = k.id
|
|
826
858
|
ORDER BY hybrid_score DESC
|
|
827
859
|
LIMIT ${tableLimit}
|
|
828
860
|
`;
|
|
@@ -833,7 +865,7 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
833
865
|
(1 - (embedding <=> $1::vector)) AS hybrid_score
|
|
834
866
|
FROM "${table}" t
|
|
835
867
|
${whereClause}
|
|
836
|
-
ORDER BY
|
|
868
|
+
ORDER BY embedding <=> $1::vector ASC
|
|
837
869
|
LIMIT ${tableLimit}
|
|
838
870
|
`;
|
|
839
871
|
params = [vectorLiteral, ...filterParams];
|
|
@@ -1039,7 +1071,11 @@ var init_MongoDBProvider = __esm({
|
|
|
1039
1071
|
if (key === "namespace") {
|
|
1040
1072
|
vectorSearchFilter.namespace = value;
|
|
1041
1073
|
} else {
|
|
1042
|
-
|
|
1074
|
+
if (typeof value === "string") {
|
|
1075
|
+
matchFilter[key] = { $regex: new RegExp(`^${value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "i") };
|
|
1076
|
+
} else {
|
|
1077
|
+
matchFilter[key] = value;
|
|
1078
|
+
}
|
|
1043
1079
|
}
|
|
1044
1080
|
}
|
|
1045
1081
|
const pipeline = [
|
|
@@ -2112,7 +2148,7 @@ function getRagConfig(baseConfig, env = process.env) {
|
|
|
2112
2148
|
return getEnvConfig(env, baseConfig);
|
|
2113
2149
|
}
|
|
2114
2150
|
function getEnvConfig(env = process.env, base) {
|
|
2115
|
-
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;
|
|
2151
|
+
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;
|
|
2116
2152
|
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__";
|
|
2117
2153
|
const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
|
|
2118
2154
|
const llmProvider = readEnum(env, "LLM_PROVIDER", "openai", LLM_PROVIDERS);
|
|
@@ -2182,7 +2218,7 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2182
2218
|
rest: "default",
|
|
2183
2219
|
custom: "default"
|
|
2184
2220
|
};
|
|
2185
|
-
return {
|
|
2221
|
+
return __spreadValues({
|
|
2186
2222
|
projectId,
|
|
2187
2223
|
vectorDb: {
|
|
2188
2224
|
provider: vectorProvider,
|
|
@@ -2198,7 +2234,9 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2198
2234
|
maxTokens: readNumber(env, "LLM_MAX_TOKENS", 4096),
|
|
2199
2235
|
temperature: readNumber(env, "LLM_TEMPERATURE", 0.7),
|
|
2200
2236
|
options: {
|
|
2201
|
-
profile: readString(env, "LLM_UNIVERSAL_PROFILE")
|
|
2237
|
+
profile: readString(env, "LLM_UNIVERSAL_PROFILE"),
|
|
2238
|
+
thinking: readString(env, "LLM_THINKING") === "true" || readString(env, "LLM_THINKING") === "enabled" ? true : readString(env, "LLM_THINKING") === "false" ? false : void 0,
|
|
2239
|
+
thinkingBudget: env.LLM_THINKING_BUDGET ? parseInt(env.LLM_THINKING_BUDGET, 10) : void 0
|
|
2202
2240
|
}
|
|
2203
2241
|
},
|
|
2204
2242
|
embedding: {
|
|
@@ -2230,11 +2268,76 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2230
2268
|
topK: readNumber(env, "RAG_TOP_K", 5),
|
|
2231
2269
|
scoreThreshold: readNumber(env, "RAG_SCORE_THRESHOLD", 0),
|
|
2232
2270
|
chunkSize: readNumber(env, "RAG_CHUNK_SIZE", 1e3),
|
|
2233
|
-
chunkOverlap: readNumber(env, "RAG_CHUNK_OVERLAP", 200)
|
|
2271
|
+
chunkOverlap: readNumber(env, "RAG_CHUNK_OVERLAP", 200),
|
|
2272
|
+
filterableFields: (_Ha = readString(env, "RAG_FILTERABLE_FIELDS")) == null ? void 0 : _Ha.split(",").map((f) => f.trim()),
|
|
2273
|
+
// Query pipeline toggles — read from .env.local
|
|
2274
|
+
useQueryTransformation: readString(env, "RAG_USE_QUERY_TRANSFORMATION") === "true",
|
|
2275
|
+
useReranking: readString(env, "RAG_USE_RERANKING") === "true",
|
|
2276
|
+
useGraphRetrieval: readString(env, "RAG_USE_GRAPH_RETRIEVAL") === "true",
|
|
2277
|
+
architecture: (_Ia = readString(env, "RAG_ARCHITECTURE")) != null ? _Ia : "simple",
|
|
2278
|
+
chunkingStrategy: (_Ja = readString(env, "RAG_CHUNKING_STRATEGY")) != null ? _Ja : "recursive",
|
|
2279
|
+
uiMapping: (() => {
|
|
2280
|
+
const raw = readString(env, "RAG_UI_MAPPING");
|
|
2281
|
+
if (!raw) return void 0;
|
|
2282
|
+
try {
|
|
2283
|
+
return JSON.parse(raw);
|
|
2284
|
+
} catch (e) {
|
|
2285
|
+
return void 0;
|
|
2286
|
+
}
|
|
2287
|
+
})()
|
|
2234
2288
|
}
|
|
2235
|
-
}
|
|
2289
|
+
}, readString(env, "GRAPH_DB_PROVIDER") ? {
|
|
2290
|
+
graphDb: {
|
|
2291
|
+
provider: readString(env, "GRAPH_DB_PROVIDER"),
|
|
2292
|
+
options: {
|
|
2293
|
+
uri: readString(env, "GRAPH_DB_URI"),
|
|
2294
|
+
username: readString(env, "GRAPH_DB_USERNAME"),
|
|
2295
|
+
password: readString(env, "GRAPH_DB_PASSWORD")
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2298
|
+
} : {});
|
|
2236
2299
|
}
|
|
2237
2300
|
|
|
2301
|
+
// src/exceptions/index.ts
|
|
2302
|
+
var RetrivoraError = class extends Error {
|
|
2303
|
+
constructor(message, code, details) {
|
|
2304
|
+
super(message);
|
|
2305
|
+
this.name = new.target.name;
|
|
2306
|
+
this.code = code;
|
|
2307
|
+
this.details = details;
|
|
2308
|
+
}
|
|
2309
|
+
};
|
|
2310
|
+
var ProviderNotFoundException = class extends RetrivoraError {
|
|
2311
|
+
constructor(providerType, provider, details) {
|
|
2312
|
+
super(`Unsupported ${providerType} provider: ${provider}`, "PROVIDER_NOT_FOUND", details);
|
|
2313
|
+
}
|
|
2314
|
+
};
|
|
2315
|
+
var EmbeddingFailedException = class extends RetrivoraError {
|
|
2316
|
+
constructor(message = "Embedding generation failed", details) {
|
|
2317
|
+
super(message, "EMBEDDING_FAILED", details);
|
|
2318
|
+
}
|
|
2319
|
+
};
|
|
2320
|
+
var RetrievalException = class extends RetrivoraError {
|
|
2321
|
+
constructor(message = "Retrieval failed", details) {
|
|
2322
|
+
super(message, "RETRIEVAL_FAILED", details);
|
|
2323
|
+
}
|
|
2324
|
+
};
|
|
2325
|
+
var RateLimitException = class extends RetrivoraError {
|
|
2326
|
+
constructor(message = "Provider rate limit exceeded", details) {
|
|
2327
|
+
super(message, "RATE_LIMITED", details);
|
|
2328
|
+
}
|
|
2329
|
+
};
|
|
2330
|
+
var ConfigurationException = class extends RetrivoraError {
|
|
2331
|
+
constructor(message, details) {
|
|
2332
|
+
super(message, "CONFIGURATION_ERROR", details);
|
|
2333
|
+
}
|
|
2334
|
+
};
|
|
2335
|
+
var AuthenticationException = class extends RetrivoraError {
|
|
2336
|
+
constructor(message = "Provider authentication failed", details) {
|
|
2337
|
+
super(message, "AUTHENTICATION_ERROR", details);
|
|
2338
|
+
}
|
|
2339
|
+
};
|
|
2340
|
+
|
|
2238
2341
|
// src/core/ConfigResolver.ts
|
|
2239
2342
|
var ConfigResolver = class {
|
|
2240
2343
|
/**
|
|
@@ -2261,24 +2364,81 @@ var ConfigResolver = class {
|
|
|
2261
2364
|
rag: hostConfig.rag ? __spreadValues(__spreadValues({}, envConfig.rag), hostConfig.rag) : envConfig.rag
|
|
2262
2365
|
});
|
|
2263
2366
|
}
|
|
2367
|
+
/**
|
|
2368
|
+
* Resolves the public SDK config shape used by `new Retrivora({...})`.
|
|
2369
|
+
* Supports aliases from the product prompt while preserving existing env
|
|
2370
|
+
* fallback behavior.
|
|
2371
|
+
*/
|
|
2372
|
+
static resolveUniversal(hostConfig, env = process.env) {
|
|
2373
|
+
var _a;
|
|
2374
|
+
if (!hostConfig) return this.resolve(void 0, env);
|
|
2375
|
+
const normalized = __spreadProps(__spreadValues({}, hostConfig), {
|
|
2376
|
+
vectorDb: (_a = hostConfig.vectorDb) != null ? _a : hostConfig.vectorDatabase,
|
|
2377
|
+
rag: this.mergeRetrievalWorkflow(hostConfig.rag, hostConfig.retrieval, hostConfig.workflow)
|
|
2378
|
+
});
|
|
2379
|
+
return this.resolve(normalized, env);
|
|
2380
|
+
}
|
|
2264
2381
|
/**
|
|
2265
2382
|
* Validates the configuration for required fields.
|
|
2266
2383
|
*/
|
|
2267
2384
|
static validate(config) {
|
|
2268
2385
|
if (!config.projectId) {
|
|
2269
|
-
throw new
|
|
2386
|
+
throw new ConfigurationException("[ConfigResolver] projectId is required");
|
|
2270
2387
|
}
|
|
2271
2388
|
if (!config.vectorDb.provider) {
|
|
2272
|
-
throw new
|
|
2389
|
+
throw new ConfigurationException("[ConfigResolver] vectorDb.provider is required");
|
|
2273
2390
|
}
|
|
2274
2391
|
if (!config.llm.provider) {
|
|
2275
|
-
throw new
|
|
2392
|
+
throw new ConfigurationException("[ConfigResolver] llm.provider is required");
|
|
2276
2393
|
}
|
|
2277
2394
|
}
|
|
2395
|
+
static mergeRetrievalWorkflow(rag, retrieval, workflow) {
|
|
2396
|
+
var _a, _b, _c, _d, _e;
|
|
2397
|
+
if (!rag && !retrieval && !workflow) return void 0;
|
|
2398
|
+
const normalized = __spreadValues({}, rag != null ? rag : {});
|
|
2399
|
+
if (retrieval) {
|
|
2400
|
+
normalized.topK = (_a = retrieval.topK) != null ? _a : normalized.topK;
|
|
2401
|
+
normalized.scoreThreshold = (_b = retrieval.scoreThreshold) != null ? _b : normalized.scoreThreshold;
|
|
2402
|
+
normalized.useReranking = (_c = retrieval.useReranking) != null ? _c : normalized.useReranking;
|
|
2403
|
+
if (retrieval.strategy === "hybrid") normalized.architecture = (_d = normalized.architecture) != null ? _d : "hybrid";
|
|
2404
|
+
if (retrieval.strategy === "agentic") normalized.architecture = "agentic";
|
|
2405
|
+
if (retrieval.strategy === "contextual-compression") normalized.useReranking = true;
|
|
2406
|
+
}
|
|
2407
|
+
if (workflow == null ? void 0 : workflow.type) {
|
|
2408
|
+
const type = workflow.type;
|
|
2409
|
+
if (type === "agentic" || type === "agentic-rag") normalized.architecture = "agentic";
|
|
2410
|
+
else if (type === "hybrid-rag") normalized.architecture = "hybrid";
|
|
2411
|
+
else if (type === "graph-rag") {
|
|
2412
|
+
normalized.architecture = "graph";
|
|
2413
|
+
normalized.useGraphRetrieval = true;
|
|
2414
|
+
} else if (type === "simple-rag" || type === "rag") {
|
|
2415
|
+
normalized.architecture = (_e = normalized.architecture) != null ? _e : "simple";
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2418
|
+
return normalized;
|
|
2419
|
+
}
|
|
2278
2420
|
};
|
|
2279
2421
|
|
|
2280
2422
|
// src/llm/providers/OpenAIProvider.ts
|
|
2281
2423
|
import OpenAI from "openai";
|
|
2424
|
+
|
|
2425
|
+
// src/llm/utils.ts
|
|
2426
|
+
function buildSystemContent(systemPrompt, context) {
|
|
2427
|
+
const noContext = !context || context.trim() === "" || context.trim() === "No relevant context found.";
|
|
2428
|
+
if (systemPrompt.includes("{{context}}")) {
|
|
2429
|
+
return systemPrompt.replace("{{context}}", noContext ? "" : context);
|
|
2430
|
+
}
|
|
2431
|
+
if (noContext) {
|
|
2432
|
+
return systemPrompt;
|
|
2433
|
+
}
|
|
2434
|
+
return `${systemPrompt}
|
|
2435
|
+
|
|
2436
|
+
---
|
|
2437
|
+
Context:
|
|
2438
|
+
${context}`;
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2441
|
+
// src/llm/providers/OpenAIProvider.ts
|
|
2282
2442
|
var OpenAIProvider = class {
|
|
2283
2443
|
constructor(llmConfig, embeddingConfig) {
|
|
2284
2444
|
if (!llmConfig.apiKey) throw new Error("[OpenAIProvider] llmConfig.apiKey is required");
|
|
@@ -2342,16 +2502,10 @@ var OpenAIProvider = class {
|
|
|
2342
2502
|
}
|
|
2343
2503
|
async chat(messages, context, options) {
|
|
2344
2504
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
2345
|
-
const
|
|
2346
|
-
|
|
2347
|
-
Context:
|
|
2348
|
-
${context}`;
|
|
2505
|
+
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.";
|
|
2349
2506
|
const systemMessage = {
|
|
2350
2507
|
role: "system",
|
|
2351
|
-
content:
|
|
2352
|
-
|
|
2353
|
-
Context:
|
|
2354
|
-
${context}`
|
|
2508
|
+
content: buildSystemContent(basePrompt, context)
|
|
2355
2509
|
};
|
|
2356
2510
|
const formattedMessages = [
|
|
2357
2511
|
systemMessage,
|
|
@@ -2372,16 +2526,10 @@ ${context}`
|
|
|
2372
2526
|
chatStream(messages, context, options) {
|
|
2373
2527
|
return __asyncGenerator(this, null, function* () {
|
|
2374
2528
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
2375
|
-
const
|
|
2376
|
-
|
|
2377
|
-
Context:
|
|
2378
|
-
${context}`;
|
|
2529
|
+
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.";
|
|
2379
2530
|
const systemMessage = {
|
|
2380
2531
|
role: "system",
|
|
2381
|
-
content:
|
|
2382
|
-
|
|
2383
|
-
Context:
|
|
2384
|
-
${context}`
|
|
2532
|
+
content: buildSystemContent(basePrompt, context)
|
|
2385
2533
|
};
|
|
2386
2534
|
const formattedMessages = [
|
|
2387
2535
|
systemMessage,
|
|
@@ -2502,58 +2650,87 @@ var AnthropicProvider = class {
|
|
|
2502
2650
|
};
|
|
2503
2651
|
}
|
|
2504
2652
|
async chat(messages, context, options) {
|
|
2505
|
-
var _a, _b, _c, _d;
|
|
2506
|
-
const
|
|
2507
|
-
|
|
2508
|
-
Context:
|
|
2509
|
-
${context}`;
|
|
2510
|
-
const system = resolvedPrompt.includes("{{context}}") ? resolvedPrompt.replace("{{context}}", context) : (options == null ? void 0 : options.systemPrompt) ? resolvedPrompt : `${resolvedPrompt}
|
|
2511
|
-
|
|
2512
|
-
Context:
|
|
2513
|
-
${context}`;
|
|
2653
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
2654
|
+
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.";
|
|
2655
|
+
const system = buildSystemContent(basePrompt, context);
|
|
2514
2656
|
const anthropicMessages = messages.map((m) => ({
|
|
2515
2657
|
role: m.role === "assistant" ? "assistant" : "user",
|
|
2516
2658
|
content: m.content
|
|
2517
2659
|
}));
|
|
2518
|
-
const
|
|
2660
|
+
const isClaude37 = this.llmConfig.model.includes("claude-3-7-sonnet");
|
|
2661
|
+
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;
|
|
2662
|
+
const extraParams = {};
|
|
2663
|
+
if (isThinkingEnabled && isClaude37) {
|
|
2664
|
+
extraParams.betas = ["interleaved-thinking-2025-05-14"];
|
|
2665
|
+
const maxTokens = (_g = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g : 4096;
|
|
2666
|
+
const budget = Math.min(
|
|
2667
|
+
typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
|
|
2668
|
+
maxTokens - 1
|
|
2669
|
+
);
|
|
2670
|
+
extraParams.thinking = {
|
|
2671
|
+
type: "enabled",
|
|
2672
|
+
budget_tokens: budget
|
|
2673
|
+
};
|
|
2674
|
+
extraParams.max_tokens = Math.max(maxTokens, budget + 1024);
|
|
2675
|
+
}
|
|
2676
|
+
const response = await this.client.messages.create(__spreadValues({
|
|
2519
2677
|
model: this.llmConfig.model,
|
|
2520
|
-
max_tokens: (
|
|
2678
|
+
max_tokens: (_k = (_j = options == null ? void 0 : options.maxTokens) != null ? _j : this.llmConfig.maxTokens) != null ? _k : 1024,
|
|
2521
2679
|
system,
|
|
2522
2680
|
messages: anthropicMessages
|
|
2523
|
-
});
|
|
2524
|
-
|
|
2525
|
-
|
|
2681
|
+
}, extraParams));
|
|
2682
|
+
let reply = "";
|
|
2683
|
+
for (const block of response.content) {
|
|
2684
|
+
if (block.type === "text") {
|
|
2685
|
+
reply += block.text;
|
|
2686
|
+
}
|
|
2687
|
+
}
|
|
2688
|
+
return reply;
|
|
2526
2689
|
}
|
|
2527
2690
|
chatStream(messages, context, options) {
|
|
2528
2691
|
return __asyncGenerator(this, null, function* () {
|
|
2529
|
-
var _a, _b, _c, _d;
|
|
2530
|
-
const
|
|
2531
|
-
|
|
2532
|
-
Context:
|
|
2533
|
-
${context}`;
|
|
2534
|
-
const system = resolvedPrompt.includes("{{context}}") ? resolvedPrompt.replace("{{context}}", context) : (options == null ? void 0 : options.systemPrompt) ? resolvedPrompt : `${resolvedPrompt}
|
|
2535
|
-
|
|
2536
|
-
Context:
|
|
2537
|
-
${context}`;
|
|
2692
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
2693
|
+
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.";
|
|
2694
|
+
const system = buildSystemContent(basePrompt, context);
|
|
2538
2695
|
const anthropicMessages = messages.map((m) => ({
|
|
2539
2696
|
role: m.role === "assistant" ? "assistant" : "user",
|
|
2540
2697
|
content: m.content
|
|
2541
2698
|
}));
|
|
2542
|
-
const
|
|
2699
|
+
const isClaude37 = this.llmConfig.model.includes("claude-3-7-sonnet");
|
|
2700
|
+
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;
|
|
2701
|
+
const extraParams = {};
|
|
2702
|
+
if (isThinkingEnabled && isClaude37) {
|
|
2703
|
+
extraParams.betas = ["interleaved-thinking-2025-05-14"];
|
|
2704
|
+
const maxTokens = (_g = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g : 4096;
|
|
2705
|
+
const budget = Math.min(
|
|
2706
|
+
typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
|
|
2707
|
+
maxTokens - 1
|
|
2708
|
+
);
|
|
2709
|
+
extraParams.thinking = {
|
|
2710
|
+
type: "enabled",
|
|
2711
|
+
budget_tokens: budget
|
|
2712
|
+
};
|
|
2713
|
+
extraParams.max_tokens = Math.max(maxTokens, budget + 1024);
|
|
2714
|
+
}
|
|
2715
|
+
const stream = yield new __await(this.client.messages.create(__spreadValues({
|
|
2543
2716
|
model: this.llmConfig.model,
|
|
2544
|
-
max_tokens: (
|
|
2717
|
+
max_tokens: (_k = (_j = options == null ? void 0 : options.maxTokens) != null ? _j : this.llmConfig.maxTokens) != null ? _k : 1024,
|
|
2545
2718
|
system,
|
|
2546
2719
|
messages: anthropicMessages,
|
|
2547
2720
|
stream: true
|
|
2548
|
-
}));
|
|
2721
|
+
}, extraParams)));
|
|
2549
2722
|
if (!stream) {
|
|
2550
2723
|
throw new Error("[AnthropicProvider] messages.create stream is undefined");
|
|
2551
2724
|
}
|
|
2552
2725
|
try {
|
|
2553
2726
|
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
2554
2727
|
const chunk = temp.value;
|
|
2555
|
-
if (chunk.type === "content_block_delta"
|
|
2556
|
-
|
|
2728
|
+
if (chunk.type === "content_block_delta") {
|
|
2729
|
+
if (chunk.delta.type === "text_delta") {
|
|
2730
|
+
yield chunk.delta.text;
|
|
2731
|
+
} else if (chunk.delta.type === "thinking_delta") {
|
|
2732
|
+
yield `\0THINKING\0${chunk.delta.thinking}`;
|
|
2733
|
+
}
|
|
2557
2734
|
}
|
|
2558
2735
|
}
|
|
2559
2736
|
} catch (temp) {
|
|
@@ -2597,9 +2774,10 @@ ${context}`;
|
|
|
2597
2774
|
import axios from "axios";
|
|
2598
2775
|
var OllamaProvider = class {
|
|
2599
2776
|
constructor(llmConfig, embeddingConfig) {
|
|
2600
|
-
var _a;
|
|
2777
|
+
var _a, _b;
|
|
2601
2778
|
const baseURL = (_a = llmConfig.baseUrl) != null ? _a : "http://localhost:11434";
|
|
2602
|
-
|
|
2779
|
+
const timeout = Number((_b = llmConfig.options) == null ? void 0 : _b.timeout) || 3e5;
|
|
2780
|
+
this.http = axios.create({ baseURL, timeout });
|
|
2603
2781
|
this.llmConfig = llmConfig;
|
|
2604
2782
|
this.embeddingConfig = embeddingConfig;
|
|
2605
2783
|
}
|
|
@@ -2655,14 +2833,15 @@ var OllamaProvider = class {
|
|
|
2655
2833
|
};
|
|
2656
2834
|
}
|
|
2657
2835
|
async chat(messages, context, options) {
|
|
2658
|
-
var _a, _b, _c, _d;
|
|
2659
|
-
const
|
|
2836
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2837
|
+
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.";
|
|
2838
|
+
const system = buildSystemContent(basePrompt, context);
|
|
2660
2839
|
const { data } = await this.http.post("/api/chat", {
|
|
2661
2840
|
model: this.llmConfig.model,
|
|
2662
2841
|
stream: false,
|
|
2663
2842
|
options: {
|
|
2664
|
-
temperature: (
|
|
2665
|
-
num_predict: (
|
|
2843
|
+
temperature: (_d = (_c = options == null ? void 0 : options.temperature) != null ? _c : this.llmConfig.temperature) != null ? _d : 0.7,
|
|
2844
|
+
num_predict: (_f = (_e = options == null ? void 0 : options.maxTokens) != null ? _e : this.llmConfig.maxTokens) != null ? _f : 1024
|
|
2666
2845
|
},
|
|
2667
2846
|
messages: [
|
|
2668
2847
|
{ role: "system", content: system },
|
|
@@ -2673,14 +2852,15 @@ var OllamaProvider = class {
|
|
|
2673
2852
|
}
|
|
2674
2853
|
chatStream(messages, context, options) {
|
|
2675
2854
|
return __asyncGenerator(this, null, function* () {
|
|
2676
|
-
var _a, _b, _c, _d, _e, _f;
|
|
2677
|
-
const
|
|
2855
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
2856
|
+
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.";
|
|
2857
|
+
const system = buildSystemContent(basePrompt, context);
|
|
2678
2858
|
const response = yield new __await(this.http.post("/api/chat", {
|
|
2679
2859
|
model: this.llmConfig.model,
|
|
2680
2860
|
stream: true,
|
|
2681
2861
|
options: {
|
|
2682
|
-
temperature: (
|
|
2683
|
-
num_predict: (
|
|
2862
|
+
temperature: (_d = (_c = options == null ? void 0 : options.temperature) != null ? _c : this.llmConfig.temperature) != null ? _d : 0.7,
|
|
2863
|
+
num_predict: (_f = (_e = options == null ? void 0 : options.maxTokens) != null ? _e : this.llmConfig.maxTokens) != null ? _f : 1024
|
|
2684
2864
|
},
|
|
2685
2865
|
messages: [
|
|
2686
2866
|
{ role: "system", content: system },
|
|
@@ -2702,7 +2882,7 @@ var OllamaProvider = class {
|
|
|
2702
2882
|
if (!line.trim()) continue;
|
|
2703
2883
|
try {
|
|
2704
2884
|
const json = JSON.parse(line);
|
|
2705
|
-
if ((
|
|
2885
|
+
if ((_g = json.message) == null ? void 0 : _g.content) {
|
|
2706
2886
|
yield json.message.content;
|
|
2707
2887
|
}
|
|
2708
2888
|
if (json.done) return;
|
|
@@ -2724,26 +2904,12 @@ var OllamaProvider = class {
|
|
|
2724
2904
|
if (lineBuffer.trim()) {
|
|
2725
2905
|
try {
|
|
2726
2906
|
const json = JSON.parse(lineBuffer);
|
|
2727
|
-
if ((
|
|
2907
|
+
if ((_h = json.message) == null ? void 0 : _h.content) yield json.message.content;
|
|
2728
2908
|
} catch (e) {
|
|
2729
2909
|
}
|
|
2730
2910
|
}
|
|
2731
2911
|
});
|
|
2732
2912
|
}
|
|
2733
|
-
buildSystemPrompt(context, overridePrompt) {
|
|
2734
|
-
var _a;
|
|
2735
|
-
if (overridePrompt) {
|
|
2736
|
-
return overridePrompt;
|
|
2737
|
-
}
|
|
2738
|
-
const systemPrompt = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Use the provided context to answer the user's question.
|
|
2739
|
-
|
|
2740
|
-
Context:
|
|
2741
|
-
${context}`;
|
|
2742
|
-
return systemPrompt.includes("{{context}}") ? systemPrompt.replace("{{context}}", context) : `${systemPrompt}
|
|
2743
|
-
|
|
2744
|
-
Context:
|
|
2745
|
-
${context}`;
|
|
2746
|
-
}
|
|
2747
2913
|
async embed(text, options) {
|
|
2748
2914
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
2749
2915
|
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";
|
|
@@ -2890,21 +3056,6 @@ var GeminiProvider = class {
|
|
|
2890
3056
|
var _a, _b;
|
|
2891
3057
|
return sanitizeModel((_b = optionsModel != null ? optionsModel : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _b : DEFAULT_EMBEDDING_MODEL);
|
|
2892
3058
|
}
|
|
2893
|
-
/**
|
|
2894
|
-
* Build the system instruction string, inserting the RAG context either via
|
|
2895
|
-
* the `{{context}}` placeholder or by appending it.
|
|
2896
|
-
*/
|
|
2897
|
-
buildSystemInstruction(context) {
|
|
2898
|
-
var _a;
|
|
2899
|
-
const base = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Answer questions based on the provided context.
|
|
2900
|
-
|
|
2901
|
-
Context:
|
|
2902
|
-
${context}`;
|
|
2903
|
-
return base.includes("{{context}}") ? base.replace("{{context}}", context) : `${base}
|
|
2904
|
-
|
|
2905
|
-
Context:
|
|
2906
|
-
${context}`;
|
|
2907
|
-
}
|
|
2908
3059
|
/**
|
|
2909
3060
|
* Convert ChatMessage[] to the Gemini contents format.
|
|
2910
3061
|
*
|
|
@@ -2923,16 +3074,17 @@ ${context}`;
|
|
|
2923
3074
|
// ILLMProvider — chat
|
|
2924
3075
|
// -------------------------------------------------------------------------
|
|
2925
3076
|
async chat(messages, context, options) {
|
|
2926
|
-
var _a, _b, _c, _d;
|
|
3077
|
+
var _a, _b, _c, _d, _e, _f;
|
|
3078
|
+
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.";
|
|
2927
3079
|
const model = this.client.getGenerativeModel({
|
|
2928
3080
|
model: this.llmConfig.model,
|
|
2929
|
-
systemInstruction:
|
|
3081
|
+
systemInstruction: buildSystemContent(basePrompt, context)
|
|
2930
3082
|
});
|
|
2931
3083
|
const result = await model.generateContent({
|
|
2932
3084
|
contents: this.buildGeminiContents(messages),
|
|
2933
3085
|
generationConfig: {
|
|
2934
|
-
temperature: (
|
|
2935
|
-
maxOutputTokens: (
|
|
3086
|
+
temperature: (_d = (_c = options == null ? void 0 : options.temperature) != null ? _c : this.llmConfig.temperature) != null ? _d : DEFAULT_TEMPERATURE,
|
|
3087
|
+
maxOutputTokens: (_f = (_e = options == null ? void 0 : options.maxTokens) != null ? _e : this.llmConfig.maxTokens) != null ? _f : DEFAULT_MAX_TOKENS,
|
|
2936
3088
|
stopSequences: options == null ? void 0 : options.stop
|
|
2937
3089
|
}
|
|
2938
3090
|
});
|
|
@@ -2940,16 +3092,17 @@ ${context}`;
|
|
|
2940
3092
|
}
|
|
2941
3093
|
chatStream(messages, context, options) {
|
|
2942
3094
|
return __asyncGenerator(this, null, function* () {
|
|
2943
|
-
var _a, _b, _c, _d;
|
|
3095
|
+
var _a, _b, _c, _d, _e, _f;
|
|
3096
|
+
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.";
|
|
2944
3097
|
const model = this.client.getGenerativeModel({
|
|
2945
3098
|
model: this.llmConfig.model,
|
|
2946
|
-
systemInstruction:
|
|
3099
|
+
systemInstruction: buildSystemContent(basePrompt, context)
|
|
2947
3100
|
});
|
|
2948
3101
|
const result = yield new __await(model.generateContentStream({
|
|
2949
3102
|
contents: this.buildGeminiContents(messages),
|
|
2950
3103
|
generationConfig: {
|
|
2951
|
-
temperature: (
|
|
2952
|
-
maxOutputTokens: (
|
|
3104
|
+
temperature: (_d = (_c = options == null ? void 0 : options.temperature) != null ? _c : this.llmConfig.temperature) != null ? _d : DEFAULT_TEMPERATURE,
|
|
3105
|
+
maxOutputTokens: (_f = (_e = options == null ? void 0 : options.maxTokens) != null ? _e : this.llmConfig.maxTokens) != null ? _f : DEFAULT_MAX_TOKENS,
|
|
2953
3106
|
stopSequences: options == null ? void 0 : options.stop
|
|
2954
3107
|
}
|
|
2955
3108
|
}));
|
|
@@ -3384,7 +3537,9 @@ var LLMFactory = class _LLMFactory {
|
|
|
3384
3537
|
if (llmConfig.baseUrl || ((_b = llmConfig.options) == null ? void 0 : _b.baseUrl)) {
|
|
3385
3538
|
return new UniversalLLMAdapter(llmConfig);
|
|
3386
3539
|
}
|
|
3387
|
-
throw new
|
|
3540
|
+
throw new ProviderNotFoundException(
|
|
3541
|
+
"LLM",
|
|
3542
|
+
String(llmConfig.provider),
|
|
3388
3543
|
`[LLMFactory] Unknown provider "${llmConfig.provider}". Built-in providers: ${_LLMFactory.listProviders().join(", ")}. Register a custom provider with LLMFactory.register().`
|
|
3389
3544
|
);
|
|
3390
3545
|
}
|
|
@@ -3516,7 +3671,7 @@ var ProviderRegistry = class {
|
|
|
3516
3671
|
return UniversalVectorProvider2;
|
|
3517
3672
|
}
|
|
3518
3673
|
default:
|
|
3519
|
-
throw new
|
|
3674
|
+
throw new ProviderNotFoundException("vector", provider);
|
|
3520
3675
|
}
|
|
3521
3676
|
}
|
|
3522
3677
|
static async createVectorProvider(config) {
|
|
@@ -3534,12 +3689,18 @@ var ProviderRegistry = class {
|
|
|
3534
3689
|
return new SimpleGraphProvider2(config);
|
|
3535
3690
|
}
|
|
3536
3691
|
default:
|
|
3537
|
-
throw new
|
|
3692
|
+
throw new ProviderNotFoundException("graph", provider);
|
|
3538
3693
|
}
|
|
3539
3694
|
}
|
|
3540
3695
|
static createLLMProvider(llmConfig, embeddingConfig) {
|
|
3541
3696
|
return LLMFactory.create(llmConfig, embeddingConfig);
|
|
3542
3697
|
}
|
|
3698
|
+
static registerLLMProvider(name, factory) {
|
|
3699
|
+
LLMFactory.register(name, factory);
|
|
3700
|
+
}
|
|
3701
|
+
static createEmbeddingProvider(embeddingConfig) {
|
|
3702
|
+
return LLMFactory.createEmbeddingProvider(embeddingConfig);
|
|
3703
|
+
}
|
|
3543
3704
|
};
|
|
3544
3705
|
ProviderRegistry.vectorProviders = {};
|
|
3545
3706
|
ProviderRegistry.graphProviders = {};
|
|
@@ -3686,8 +3847,8 @@ var ConfigValidator = class {
|
|
|
3686
3847
|
const errorItems = errors.filter((e) => e.severity === "error");
|
|
3687
3848
|
if (errorItems.length > 0) {
|
|
3688
3849
|
const message = errorItems.map((e) => `${e.field}: ${e.message}${e.suggestion ? ` (${e.suggestion})` : ""}`).join("\n ");
|
|
3689
|
-
throw new
|
|
3690
|
-
${message}
|
|
3850
|
+
throw new ConfigurationException(`[ConfigValidator] Configuration validation failed:
|
|
3851
|
+
${message}`, errorItems);
|
|
3691
3852
|
}
|
|
3692
3853
|
}
|
|
3693
3854
|
};
|
|
@@ -3874,20 +4035,17 @@ var Reranker = class {
|
|
|
3874
4035
|
}
|
|
3875
4036
|
try {
|
|
3876
4037
|
const topN = matches.slice(0, 10);
|
|
3877
|
-
const
|
|
3878
|
-
|
|
3879
|
-
Return the result as a comma-separated list of document indices in order of relevance, from most relevant to least relevant.
|
|
3880
|
-
Use the indices provided in brackets like [0], [1], etc.
|
|
3881
|
-
Only return the indices (e.g., "2,0,1"), nothing else. Do not include brackets in the output.
|
|
3882
|
-
|
|
3883
|
-
Query: "${query}"
|
|
4038
|
+
const response = await llm.chat(
|
|
4039
|
+
[{ role: "user", content: `Query: "${query}"
|
|
3884
4040
|
|
|
3885
4041
|
Documents:
|
|
3886
|
-
${topN.map((m, i) => `[${i}] ${m.content.replace(/\n/g, " ")}`).join("\n")}
|
|
3887
|
-
const response = await llm.chat(
|
|
3888
|
-
[{ role: "user", content: prompt }],
|
|
4042
|
+
${topN.map((m, i) => `[${i}] ${m.content.replace(/\n/g, " ")}`).join("\n")}` }],
|
|
3889
4043
|
"",
|
|
3890
|
-
{
|
|
4044
|
+
{
|
|
4045
|
+
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.',
|
|
4046
|
+
temperature: 0,
|
|
4047
|
+
maxTokens: 50
|
|
4048
|
+
}
|
|
3891
4049
|
);
|
|
3892
4050
|
const cleanedResponse = response.trim().replace(/[\[\]\s]/g, "");
|
|
3893
4051
|
const rankedIndices = cleanedResponse.split(",").map(Number).filter((n) => !isNaN(n));
|
|
@@ -4399,6 +4557,18 @@ var QueryProcessor = class {
|
|
|
4399
4557
|
}, normalizedField ? { field: normalizedField } : {}));
|
|
4400
4558
|
}
|
|
4401
4559
|
};
|
|
4560
|
+
const activeValidFields = validFields.length > 0 ? validFields : ["brand", "category", "price", "rating", "stock", "stock_quantity", "status", "name", "title"];
|
|
4561
|
+
const resolveValidField = (fieldStr) => {
|
|
4562
|
+
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();
|
|
4563
|
+
const comparable = (v) => v.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
4564
|
+
const cleanedComparable = comparable(cleaned);
|
|
4565
|
+
if (!cleanedComparable) return null;
|
|
4566
|
+
const matchedField = activeValidFields.find((fieldName) => {
|
|
4567
|
+
const candidate = comparable(fieldName);
|
|
4568
|
+
return candidate === cleanedComparable || candidate.includes(cleanedComparable) || cleanedComparable.includes(candidate);
|
|
4569
|
+
});
|
|
4570
|
+
return matchedField != null ? matchedField : null;
|
|
4571
|
+
};
|
|
4402
4572
|
for (const match of question.matchAll(/["']([^"']{2,100})["']/g)) {
|
|
4403
4573
|
addHint(match[1]);
|
|
4404
4574
|
}
|
|
@@ -4423,7 +4593,13 @@ var QueryProcessor = class {
|
|
|
4423
4593
|
const field = match[1];
|
|
4424
4594
|
const value = match[2];
|
|
4425
4595
|
if (field && !this.isLikelyPromptPhrase(field)) {
|
|
4426
|
-
|
|
4596
|
+
const resolvedField = resolveValidField(field);
|
|
4597
|
+
if (resolvedField) {
|
|
4598
|
+
addHint(value, resolvedField);
|
|
4599
|
+
} else {
|
|
4600
|
+
addHint(value);
|
|
4601
|
+
addHint(field);
|
|
4602
|
+
}
|
|
4427
4603
|
}
|
|
4428
4604
|
}
|
|
4429
4605
|
if (validFields.length > 0) {
|
|
@@ -4469,12 +4645,16 @@ var QueryProcessor = class {
|
|
|
4469
4645
|
];
|
|
4470
4646
|
for (const pattern of fieldValuePatterns) {
|
|
4471
4647
|
for (const match of question.matchAll(pattern)) {
|
|
4472
|
-
const field =
|
|
4648
|
+
const field = (_c = match[1]) != null ? _c : "";
|
|
4473
4649
|
const value = (_d = match[2]) != null ? _d : "";
|
|
4474
|
-
|
|
4475
|
-
|
|
4650
|
+
const resolvedField = resolveValidField(field);
|
|
4651
|
+
if (resolvedField) {
|
|
4652
|
+
addHint(value, resolvedField);
|
|
4476
4653
|
} else {
|
|
4477
4654
|
addHint(value);
|
|
4655
|
+
if (field && !this.isLikelyPromptPhrase(field)) {
|
|
4656
|
+
addHint(field);
|
|
4657
|
+
}
|
|
4478
4658
|
}
|
|
4479
4659
|
}
|
|
4480
4660
|
}
|
|
@@ -4701,7 +4881,7 @@ var LLMRouter = class {
|
|
|
4701
4881
|
|
|
4702
4882
|
// src/utils/UITransformer.ts
|
|
4703
4883
|
init_synonyms();
|
|
4704
|
-
var UITransformer = class {
|
|
4884
|
+
var UITransformer = class _UITransformer {
|
|
4705
4885
|
// ─── Public Entry Points ─────────────────────────────────────────────────
|
|
4706
4886
|
/**
|
|
4707
4887
|
* Heuristic-only transform (no LLM required).
|
|
@@ -4763,7 +4943,7 @@ var UITransformer = class {
|
|
|
4763
4943
|
static async analyzeAndDecide(query, sources, llm) {
|
|
4764
4944
|
let intent;
|
|
4765
4945
|
try {
|
|
4766
|
-
intent = await this.detectIntent(query, llm);
|
|
4946
|
+
intent = await this.detectIntent(query, llm, sources);
|
|
4767
4947
|
console.debug("[UITransformer] Detected intent:", intent);
|
|
4768
4948
|
} catch (err) {
|
|
4769
4949
|
console.warn("[UITransformer] Intent detection failed; using heuristic.", err);
|
|
@@ -4781,11 +4961,23 @@ var UITransformer = class {
|
|
|
4781
4961
|
try {
|
|
4782
4962
|
const context = this.buildContextSummary(sources);
|
|
4783
4963
|
const systemPrompt = this.buildVisualizationSystemPrompt();
|
|
4964
|
+
const profile = this.profileData(sources);
|
|
4965
|
+
const schemaContext = `
|
|
4966
|
+
RETRIEVED DATA SCHEMA:
|
|
4967
|
+
- Numeric fields (measures): ${profile.numericFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
|
|
4968
|
+
- Category fields (dimensions): ${profile.categoricalFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
|
|
4969
|
+
- Date fields (temporal): ${profile.dateFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
|
|
4970
|
+
- Boolean fields: ${profile.booleanFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
|
|
4971
|
+
- Text/Other fields: ${profile.fields.filter((f) => f.kind === "text").map((f) => f.key).join(", ") || "None"}
|
|
4972
|
+
`;
|
|
4784
4973
|
const userPrompt = [
|
|
4785
4974
|
`USER QUESTION: ${query}`,
|
|
4786
4975
|
"",
|
|
4787
4976
|
`DETECTED INTENT (JSON): ${JSON.stringify(intent)}`,
|
|
4788
4977
|
"",
|
|
4978
|
+
`RETRIEVED DATA SCHEMA:`,
|
|
4979
|
+
schemaContext,
|
|
4980
|
+
"",
|
|
4789
4981
|
"RETRIEVED DATA (JSON):",
|
|
4790
4982
|
context
|
|
4791
4983
|
].join("\n");
|
|
@@ -4796,6 +4988,20 @@ var UITransformer = class {
|
|
|
4796
4988
|
);
|
|
4797
4989
|
const parsed = this.parseTransformationResponse(rawResponse);
|
|
4798
4990
|
if (parsed) {
|
|
4991
|
+
let isCompatible = true;
|
|
4992
|
+
if (parsed.type === "line_chart" && (profile.dateFields.length === 0 || profile.numericFields.length === 0)) {
|
|
4993
|
+
isCompatible = false;
|
|
4994
|
+
} else if (["bar_chart", "horizontal_bar", "pie_chart", "donut_chart"].includes(parsed.type) && (profile.categoricalFields.length === 0 && profile.numericFields.length === 0)) {
|
|
4995
|
+
isCompatible = false;
|
|
4996
|
+
} else if (parsed.type === "scatter_plot" && profile.numericFields.length < 2) {
|
|
4997
|
+
isCompatible = false;
|
|
4998
|
+
} else if (parsed.type === "metric_card" && profile.numericFields.length === 0) {
|
|
4999
|
+
isCompatible = false;
|
|
5000
|
+
}
|
|
5001
|
+
if (!isCompatible) {
|
|
5002
|
+
console.warn(`[UITransformer] LLM chose incompatible visualization type "${parsed.type}" for retrieved schema. Falling back to heuristic.`);
|
|
5003
|
+
return this.transform(query, sources, void 0, void 0, intent);
|
|
5004
|
+
}
|
|
4799
5005
|
const intentAllowsTable = intent.wantsExplicitTable || ["tabular", "table", "geographic"].includes(intent.visualizationHint);
|
|
4800
5006
|
const intentWantsPieLikeChart = ["pie_chart", "donut_chart"].includes(intent.recommendedChart) || ["composition", "category_breakdown"].includes(intent.visualizationHint);
|
|
4801
5007
|
if (parsed.type === "table" && !intentAllowsTable) {
|
|
@@ -4825,7 +5031,26 @@ var UITransformer = class {
|
|
|
4825
5031
|
* - The intent object can be reused across both the heuristic and LLM paths.
|
|
4826
5032
|
* - It is easy to unit-test intent detection in isolation.
|
|
4827
5033
|
*/
|
|
4828
|
-
static async detectIntent(query, llm) {
|
|
5034
|
+
static async detectIntent(query, llm, sources) {
|
|
5035
|
+
let schemaProfileText = "";
|
|
5036
|
+
if (sources && sources.length > 0) {
|
|
5037
|
+
const profile = this.profileData(sources);
|
|
5038
|
+
const hasProducts = sources.some((item) => this.isProductData(item));
|
|
5039
|
+
schemaProfileText = `
|
|
5040
|
+
RETRIEVED DATA SCHEMA:
|
|
5041
|
+
- Numeric fields (measures): ${profile.numericFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
|
|
5042
|
+
- Category fields (dimensions): ${profile.categoricalFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
|
|
5043
|
+
- Date fields (temporal): ${profile.dateFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
|
|
5044
|
+
- Boolean fields: ${profile.booleanFields.map((f) => `${f.key} (unique values: ${f.uniqueCount})`).join(", ") || "None"}
|
|
5045
|
+
- Text fields: ${profile.fields.filter((f) => f.kind === "text").map((f) => f.key).join(", ") || "None"}
|
|
5046
|
+
|
|
5047
|
+
Please choose visualizationHint and recommendedChart dynamically based on the available schema.
|
|
5048
|
+
- Do NOT recommend "trend" or "line_chart" if there are no Date fields.
|
|
5049
|
+
- 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.
|
|
5050
|
+
- If there are multiple metadata fields but no clear categories or numbers, "tabular"/"table" is a highly accurate default.
|
|
5051
|
+
${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".` : ""}
|
|
5052
|
+
`;
|
|
5053
|
+
}
|
|
4829
5054
|
const systemPrompt = `You are an intent classifier for a product-search RAG system.
|
|
4830
5055
|
Given a user query, return ONLY a valid JSON object with this exact shape \u2014 no prose, no markdown:
|
|
4831
5056
|
|
|
@@ -4861,8 +5086,11 @@ RULES:
|
|
|
4861
5086
|
- isTemporal: true if time words appear (trend, historical, over time, last year, monthly, etc.)
|
|
4862
5087
|
- isComparison: true if user compares, ranks, or contrasts entities or categories.
|
|
4863
5088
|
- language: detect from the query text itself; default "en" if uncertain.`;
|
|
5089
|
+
const userPrompt = `QUERY: ${query}${schemaProfileText ? `
|
|
5090
|
+
|
|
5091
|
+
${schemaProfileText}` : ""}`;
|
|
4864
5092
|
const rawResponse = await llm.chat(
|
|
4865
|
-
[{ role: "user", content:
|
|
5093
|
+
[{ role: "user", content: userPrompt }],
|
|
4866
5094
|
"",
|
|
4867
5095
|
{ systemPrompt, temperature: 0 }
|
|
4868
5096
|
);
|
|
@@ -5305,10 +5533,21 @@ RULES:
|
|
|
5305
5533
|
const hasEntityTerms = /\b(organization|organisations?|organizations?|company|companies|employee|employees|staff|headcount|workforce)\b/.test(q);
|
|
5306
5534
|
return asksForRecords && (hasNumericPredicate || hasEntityTerms);
|
|
5307
5535
|
}
|
|
5536
|
+
/** @internal kept private for transform() internal logic */
|
|
5308
5537
|
static isProductQuery(query) {
|
|
5538
|
+
return _UITransformer._productQueryTest(query);
|
|
5539
|
+
}
|
|
5540
|
+
/**
|
|
5541
|
+
* Public entry-point for external callers (e.g. Pipeline)
|
|
5542
|
+
* to check whether a query maps to product_browse without triggering an LLM call.
|
|
5543
|
+
*/
|
|
5544
|
+
static isProductQueryPublic(query) {
|
|
5545
|
+
return _UITransformer._productQueryTest(query);
|
|
5546
|
+
}
|
|
5547
|
+
static _productQueryTest(query) {
|
|
5309
5548
|
const q = query.toLowerCase();
|
|
5310
5549
|
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);
|
|
5311
|
-
const productAction = /\b(recommend|suggest|describe|description|detail|details|about|show|find|search|browse|list)\b/.test(q);
|
|
5550
|
+
const productAction = /\b(recommend|suggest|describe|description|detail|details|about|show|find|search|browse|list|explore|exploring)\b/.test(q);
|
|
5312
5551
|
const nonProductEntityTerms = /\b(organization|organisations?|organizations?|company|companies|employee|employees|staff|headcount|workforce)\b/.test(q);
|
|
5313
5552
|
return productTerms && productAction && !nonProductEntityTerms;
|
|
5314
5553
|
}
|
|
@@ -6081,23 +6320,19 @@ function estimateCostUsd(promptTokens, completionTokens, model) {
|
|
|
6081
6320
|
async function scoreHallucination(llm, answer, context) {
|
|
6082
6321
|
const maxContextChars = 3e3;
|
|
6083
6322
|
const truncatedContext = context.length > maxContextChars ? context.slice(0, maxContextChars) + "\n...[truncated]" : context;
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
CONTEXT:
|
|
6323
|
+
try {
|
|
6324
|
+
const raw = await llm.chat(
|
|
6325
|
+
[{ role: "user", content: `CONTEXT:
|
|
6087
6326
|
${truncatedContext}
|
|
6088
6327
|
|
|
6089
6328
|
ANSWER:
|
|
6090
|
-
${answer}
|
|
6091
|
-
|
|
6092
|
-
Return ONLY a valid JSON object with no markdown fences:
|
|
6093
|
-
{"score": <float 0-1>, "reason": "<one sentence>"}
|
|
6094
|
-
|
|
6095
|
-
Where score 0 = fully grounded in context, score 1 = likely hallucinated or unsupported.`;
|
|
6096
|
-
try {
|
|
6097
|
-
const raw = await llm.chat(
|
|
6098
|
-
[{ role: "user", content: prompt }],
|
|
6329
|
+
${answer}` }],
|
|
6099
6330
|
"",
|
|
6100
|
-
{
|
|
6331
|
+
{
|
|
6332
|
+
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.',
|
|
6333
|
+
temperature: 0,
|
|
6334
|
+
maxTokens: 120
|
|
6335
|
+
}
|
|
6101
6336
|
);
|
|
6102
6337
|
const jsonMatch = raw.match(/\{[\s\S]*\}/);
|
|
6103
6338
|
if (!jsonMatch) return void 0;
|
|
@@ -6157,7 +6392,10 @@ var Pipeline = class {
|
|
|
6157
6392
|
- 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.
|
|
6158
6393
|
- Do NOT try to format product lists as tables.
|
|
6159
6394
|
`;
|
|
6160
|
-
this.config.llm.systemPrompt
|
|
6395
|
+
const userPromptPrefix = this.config.llm.systemPrompt ? `${this.config.llm.systemPrompt}
|
|
6396
|
+
|
|
6397
|
+
` : "";
|
|
6398
|
+
this.config.llm.systemPrompt = `${userPromptPrefix}${chartInstruction}`;
|
|
6161
6399
|
this.vectorDB = await ProviderRegistry.createVectorProvider(this.config.vectorDb);
|
|
6162
6400
|
this.llmRouter = new LLMRouter(this.config);
|
|
6163
6401
|
const { llmProvider: resolvedLLM, embeddingProvider } = await EmbeddingStrategyResolver.resolve(
|
|
@@ -6335,11 +6573,11 @@ var Pipeline = class {
|
|
|
6335
6573
|
*/
|
|
6336
6574
|
askStream(_0) {
|
|
6337
6575
|
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
6338
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
6576
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v;
|
|
6339
6577
|
yield new __await(this.initialize());
|
|
6340
6578
|
const ns = namespace != null ? namespace : this.config.projectId;
|
|
6341
6579
|
const topK = (_b = (_a = this.config.rag) == null ? void 0 : _a.topK) != null ? _b : 5;
|
|
6342
|
-
const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0;
|
|
6580
|
+
const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0.3;
|
|
6343
6581
|
const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
6344
6582
|
const requestStart = performance.now();
|
|
6345
6583
|
try {
|
|
@@ -6358,12 +6596,13 @@ var Pipeline = class {
|
|
|
6358
6596
|
const embedStart = performance.now();
|
|
6359
6597
|
const cacheKey = `${ns}::${searchQuery}`;
|
|
6360
6598
|
const cachedVector = this.embeddingCache.get(cacheKey);
|
|
6599
|
+
const useGraph = this.graphDB && ((_h = this.config.rag) == null ? void 0 : _h.useGraphRetrieval);
|
|
6361
6600
|
const [strategyResult, embeddedVector] = yield new __await(Promise.all([
|
|
6362
6601
|
QueryProcessor.determineRetrievalStrategy(
|
|
6363
6602
|
searchQuery,
|
|
6364
|
-
this.llmRouter.get("fast"),
|
|
6365
|
-
(
|
|
6366
|
-
(
|
|
6603
|
+
useGraph ? this.llmRouter.get("fast") : void 0,
|
|
6604
|
+
(_i = this.config.rag) == null ? void 0 : _i.graphKeywords,
|
|
6605
|
+
(_j = this.config.rag) == null ? void 0 : _j.vectorKeywords
|
|
6367
6606
|
),
|
|
6368
6607
|
// Embed immediately regardless of strategy — costs nothing if cached.
|
|
6369
6608
|
// If strategy turns out to be 'graph'-only we just won't use the vector.
|
|
@@ -6373,7 +6612,7 @@ var Pipeline = class {
|
|
|
6373
6612
|
if (!cachedVector && queryVector.length > 0) {
|
|
6374
6613
|
this.embeddingCache.set(cacheKey, queryVector);
|
|
6375
6614
|
}
|
|
6376
|
-
const graphData = (strategyResult === "graph" || strategyResult === "both") && this.graphDB && ((
|
|
6615
|
+
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;
|
|
6377
6616
|
const hasMetadataFilter = filter.metadata && Object.keys(filter.metadata).length > 0;
|
|
6378
6617
|
const hasNumericPredicates = Array.isArray(filter.__numericPredicates) && filter.__numericPredicates.length > 0;
|
|
6379
6618
|
const wantsExhaustiveList = hasNumericPredicates || hasMetadataFilter || /\b(list|all|show|provide|give|get|browse|find|search|display)\b/i.test(question);
|
|
@@ -6386,7 +6625,7 @@ var Pipeline = class {
|
|
|
6386
6625
|
const structuredSources = this.applyStructuredFilters(rawSources, filter);
|
|
6387
6626
|
let fullSources = hasNumericPredicates ? structuredSources : structuredSources.filter((m) => m.score >= scoreThreshold);
|
|
6388
6627
|
const rerankLimit = wantsExhaustiveList ? retrievalLimit : topK;
|
|
6389
|
-
if (!hasNumericPredicates && ((
|
|
6628
|
+
if (!hasNumericPredicates && ((_l = this.config.rag) == null ? void 0 : _l.useReranking)) {
|
|
6390
6629
|
fullSources = yield new __await(this.reranker.rerank(fullSources, question, rerankLimit));
|
|
6391
6630
|
} else if (!wantsExhaustiveList) {
|
|
6392
6631
|
fullSources = fullSources.slice(0, topK);
|
|
@@ -6417,34 +6656,117 @@ VECTOR CONTEXT:
|
|
|
6417
6656
|
${context}`;
|
|
6418
6657
|
}
|
|
6419
6658
|
const allMetadataKeys = Array.from(new Set(sources.flatMap((s) => Object.keys(s.metadata || {}))));
|
|
6420
|
-
const
|
|
6421
|
-
|
|
6422
|
-
(
|
|
6659
|
+
const cachedSchema = allMetadataKeys.length > 0 ? SchemaMapper.getCached(ns, allMetadataKeys) : void 0;
|
|
6660
|
+
if (allMetadataKeys.length > 0 && !cachedSchema) {
|
|
6661
|
+
SchemaMapper.train(this.llmProvider, ns, allMetadataKeys).catch(() => {
|
|
6662
|
+
});
|
|
6663
|
+
}
|
|
6664
|
+
const isProductQ = UITransformer.isProductQueryPublic(question);
|
|
6665
|
+
const uiTransformationPromise = isProductQ ? Promise.resolve(
|
|
6666
|
+
UITransformer.transform(
|
|
6423
6667
|
question,
|
|
6424
6668
|
sources,
|
|
6425
|
-
|
|
6426
|
-
|
|
6669
|
+
this.config,
|
|
6670
|
+
cachedSchema,
|
|
6671
|
+
{ visualizationHint: "product_browse", recommendedChart: "text", filterInStockOnly: false, wantsExplicitTable: false, isTemporal: false, isComparison: false, language: "en" }
|
|
6427
6672
|
)
|
|
6673
|
+
) : this.generateUiTransformation(
|
|
6674
|
+
question,
|
|
6675
|
+
sources,
|
|
6676
|
+
cachedSchema,
|
|
6677
|
+
hasNumericPredicates
|
|
6428
6678
|
).catch((uiError) => {
|
|
6429
6679
|
console.warn("[Pipeline] UI transformation failed concurrently:", uiError);
|
|
6430
|
-
return UITransformer.transform(question, sources, this.config);
|
|
6680
|
+
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6431
6681
|
});
|
|
6682
|
+
let hallucinationScoringPromise = Promise.resolve(void 0);
|
|
6432
6683
|
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.)";
|
|
6684
|
+
const isClaude37 = this.config.llm.model.includes("claude-3-7-sonnet");
|
|
6685
|
+
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);
|
|
6686
|
+
const modelNameLower = this.config.llm.model.toLowerCase();
|
|
6687
|
+
const isReasoningModel = modelNameLower.includes("-r1") || modelNameLower.includes("deepseek-r1") || modelNameLower.includes("reasoning") || modelNameLower.includes("thinking");
|
|
6688
|
+
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);
|
|
6689
|
+
let finalRestrictionSuffix = restrictionSuffix;
|
|
6690
|
+
if (isSimulatedThinking) {
|
|
6691
|
+
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.`)";
|
|
6692
|
+
}
|
|
6433
6693
|
const hardenedHistory = [...history];
|
|
6434
|
-
const userQuestion = { role: "user", content: question +
|
|
6694
|
+
const userQuestion = { role: "user", content: question + finalRestrictionSuffix };
|
|
6435
6695
|
const messages = [...hardenedHistory, userQuestion];
|
|
6436
|
-
const systemPrompt = (
|
|
6696
|
+
const systemPrompt = (_s = this.config.llm.systemPrompt) != null ? _s : "";
|
|
6437
6697
|
const userPrompt = messages.map((m) => `${m.role}: ${m.content}`).join("\n");
|
|
6438
6698
|
let fullReply = "";
|
|
6699
|
+
let thinkingText = "";
|
|
6700
|
+
let thinkingStartMs = performance.now();
|
|
6701
|
+
let thinkingDurationMs = 0;
|
|
6439
6702
|
const generateStart = performance.now();
|
|
6440
6703
|
if (this.llmProvider.chatStream) {
|
|
6441
6704
|
const stream = this.llmProvider.chatStream(messages, context);
|
|
6442
6705
|
if (!stream) throw new Error(`[Pipeline] ${this.config.llm.provider} chatStream returned undefined`);
|
|
6706
|
+
let inThinking = false;
|
|
6707
|
+
let textBuffer = "";
|
|
6443
6708
|
try {
|
|
6444
6709
|
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
6445
6710
|
const chunk = temp.value;
|
|
6446
|
-
|
|
6447
|
-
|
|
6711
|
+
if (chunk.startsWith("\0THINKING\0")) {
|
|
6712
|
+
const thinkingDelta = chunk.slice("\0THINKING\0".length);
|
|
6713
|
+
thinkingText += thinkingDelta;
|
|
6714
|
+
thinkingDurationMs = performance.now() - thinkingStartMs;
|
|
6715
|
+
yield { type: "thinking", text: thinkingDelta };
|
|
6716
|
+
continue;
|
|
6717
|
+
}
|
|
6718
|
+
if (isSimulatedThinking) {
|
|
6719
|
+
textBuffer += chunk;
|
|
6720
|
+
while (textBuffer.length > 0) {
|
|
6721
|
+
if (!inThinking) {
|
|
6722
|
+
const thinkIndex = textBuffer.indexOf("<think>");
|
|
6723
|
+
if (thinkIndex !== -1) {
|
|
6724
|
+
const before = textBuffer.slice(0, thinkIndex);
|
|
6725
|
+
if (before) {
|
|
6726
|
+
fullReply += before;
|
|
6727
|
+
yield before;
|
|
6728
|
+
}
|
|
6729
|
+
inThinking = true;
|
|
6730
|
+
thinkingStartMs = performance.now();
|
|
6731
|
+
textBuffer = textBuffer.slice(thinkIndex + "<think>".length);
|
|
6732
|
+
} else {
|
|
6733
|
+
const maxSafeLength = textBuffer.length - "<think>".length;
|
|
6734
|
+
if (maxSafeLength > 0) {
|
|
6735
|
+
const safeText = textBuffer.slice(0, maxSafeLength);
|
|
6736
|
+
fullReply += safeText;
|
|
6737
|
+
yield safeText;
|
|
6738
|
+
textBuffer = textBuffer.slice(maxSafeLength);
|
|
6739
|
+
}
|
|
6740
|
+
break;
|
|
6741
|
+
}
|
|
6742
|
+
} else {
|
|
6743
|
+
const endThinkIndex = textBuffer.indexOf("</think>");
|
|
6744
|
+
if (endThinkIndex !== -1) {
|
|
6745
|
+
const thinkingDelta = textBuffer.slice(0, endThinkIndex);
|
|
6746
|
+
if (thinkingDelta) {
|
|
6747
|
+
thinkingText += thinkingDelta;
|
|
6748
|
+
thinkingDurationMs = performance.now() - thinkingStartMs;
|
|
6749
|
+
yield { type: "thinking", text: thinkingDelta };
|
|
6750
|
+
}
|
|
6751
|
+
inThinking = false;
|
|
6752
|
+
textBuffer = textBuffer.slice(endThinkIndex + "</think>".length);
|
|
6753
|
+
} else {
|
|
6754
|
+
const maxSafeLength = textBuffer.length - "</think>".length;
|
|
6755
|
+
if (maxSafeLength > 0) {
|
|
6756
|
+
const thinkingDelta = textBuffer.slice(0, maxSafeLength);
|
|
6757
|
+
thinkingText += thinkingDelta;
|
|
6758
|
+
thinkingDurationMs = performance.now() - thinkingStartMs;
|
|
6759
|
+
yield { type: "thinking", text: thinkingDelta };
|
|
6760
|
+
textBuffer = textBuffer.slice(maxSafeLength);
|
|
6761
|
+
}
|
|
6762
|
+
break;
|
|
6763
|
+
}
|
|
6764
|
+
}
|
|
6765
|
+
}
|
|
6766
|
+
} else {
|
|
6767
|
+
fullReply += chunk;
|
|
6768
|
+
yield chunk;
|
|
6769
|
+
}
|
|
6448
6770
|
}
|
|
6449
6771
|
} catch (temp) {
|
|
6450
6772
|
error = [temp];
|
|
@@ -6456,17 +6778,42 @@ ${context}`;
|
|
|
6456
6778
|
throw error[0];
|
|
6457
6779
|
}
|
|
6458
6780
|
}
|
|
6781
|
+
if (isSimulatedThinking && textBuffer.length > 0) {
|
|
6782
|
+
if (inThinking) {
|
|
6783
|
+
thinkingText += textBuffer;
|
|
6784
|
+
yield { type: "thinking", text: textBuffer };
|
|
6785
|
+
} else {
|
|
6786
|
+
fullReply += textBuffer;
|
|
6787
|
+
yield textBuffer;
|
|
6788
|
+
}
|
|
6789
|
+
}
|
|
6459
6790
|
} else {
|
|
6460
6791
|
const reply = yield new __await(this.llmProvider.chat(messages, context));
|
|
6461
|
-
|
|
6462
|
-
|
|
6792
|
+
if (isSimulatedThinking) {
|
|
6793
|
+
const thinkStart = reply.indexOf("<think>");
|
|
6794
|
+
const thinkEnd = reply.indexOf("</think>");
|
|
6795
|
+
if (thinkStart !== -1 && thinkEnd !== -1 && thinkEnd > thinkStart) {
|
|
6796
|
+
thinkingText = reply.slice(thinkStart + "<think>".length, thinkEnd);
|
|
6797
|
+
fullReply = reply.slice(0, thinkStart) + reply.slice(thinkEnd + "</think>".length);
|
|
6798
|
+
thinkingDurationMs = 100;
|
|
6799
|
+
} else {
|
|
6800
|
+
fullReply = reply;
|
|
6801
|
+
}
|
|
6802
|
+
} else {
|
|
6803
|
+
fullReply = reply;
|
|
6804
|
+
}
|
|
6805
|
+
yield fullReply;
|
|
6806
|
+
}
|
|
6807
|
+
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;
|
|
6808
|
+
if (runHallucination) {
|
|
6809
|
+
hallucinationScoringPromise = scoreHallucination(this.llmProvider, fullReply, context).catch(() => void 0);
|
|
6463
6810
|
}
|
|
6464
6811
|
const generateMs = performance.now() - generateStart;
|
|
6465
6812
|
const totalMs = performance.now() - requestStart;
|
|
6466
6813
|
const latency = {
|
|
6467
6814
|
embedMs: Math.round(embedMs),
|
|
6468
6815
|
retrieveMs: Math.round(retrieveMs),
|
|
6469
|
-
rerankMs: ((
|
|
6816
|
+
rerankMs: ((_v = this.config.rag) == null ? void 0 : _v.useReranking) ? Math.round(rerankMs) : void 0,
|
|
6470
6817
|
generateMs: Math.round(generateMs),
|
|
6471
6818
|
totalMs: Math.round(totalMs)
|
|
6472
6819
|
};
|
|
@@ -6479,12 +6826,16 @@ ${context}`;
|
|
|
6479
6826
|
totalTokens: promptTokens + completionTokens,
|
|
6480
6827
|
estimatedCostUsd: estimateCostUsd(promptTokens, completionTokens, this.config.llm.model)
|
|
6481
6828
|
};
|
|
6482
|
-
const
|
|
6829
|
+
const [uiTransformation, hallucinationResult] = yield new __await(Promise.all([
|
|
6830
|
+
uiTransformationPromise,
|
|
6831
|
+
hallucinationScoringPromise
|
|
6832
|
+
]));
|
|
6833
|
+
const trace = __spreadValues({
|
|
6483
6834
|
requestId,
|
|
6484
6835
|
query: question,
|
|
6485
6836
|
rewrittenQuery,
|
|
6486
6837
|
systemPrompt,
|
|
6487
|
-
userPrompt: question +
|
|
6838
|
+
userPrompt: question + finalRestrictionSuffix,
|
|
6488
6839
|
chunks: sources.map((s) => {
|
|
6489
6840
|
var _a2;
|
|
6490
6841
|
return {
|
|
@@ -6498,22 +6849,19 @@ ${context}`;
|
|
|
6498
6849
|
latency,
|
|
6499
6850
|
tokens,
|
|
6500
6851
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6501
|
-
}
|
|
6502
|
-
|
|
6852
|
+
}, hallucinationResult ? {
|
|
6853
|
+
hallucinationScore: hallucinationResult.score,
|
|
6854
|
+
hallucinationReason: hallucinationResult.reason
|
|
6855
|
+
} : {});
|
|
6503
6856
|
yield {
|
|
6504
6857
|
reply: "",
|
|
6505
6858
|
sources,
|
|
6506
6859
|
graphData,
|
|
6507
6860
|
ui_transformation: uiTransformation,
|
|
6508
|
-
trace
|
|
6861
|
+
trace,
|
|
6862
|
+
thinking: thinkingText || void 0,
|
|
6863
|
+
thinkingMs: thinkingDurationMs > 0 ? Math.round(thinkingDurationMs) : void 0
|
|
6509
6864
|
};
|
|
6510
|
-
scoreHallucination(this.llmProvider, fullReply, context).then((hallucinationResult) => {
|
|
6511
|
-
if (hallucinationResult) {
|
|
6512
|
-
trace.hallucinationScore = hallucinationResult.score;
|
|
6513
|
-
trace.hallucinationReason = hallucinationResult.reason;
|
|
6514
|
-
}
|
|
6515
|
-
}).catch(() => {
|
|
6516
|
-
});
|
|
6517
6865
|
} catch (error2) {
|
|
6518
6866
|
throw new Error(`[Pipeline] Stream failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
6519
6867
|
}
|
|
@@ -6523,18 +6871,30 @@ ${context}`;
|
|
|
6523
6871
|
* Universal retrieval method combining all enabled providers.
|
|
6524
6872
|
* Uses an LRU-bounded embedding cache to avoid re-embedding the same query.
|
|
6525
6873
|
*/
|
|
6526
|
-
async generateUiTransformation(question, sources,
|
|
6874
|
+
async generateUiTransformation(question, sources, cachedSchema, forceDeterministic = false) {
|
|
6875
|
+
var _a;
|
|
6527
6876
|
if (!sources || sources.length === 0) {
|
|
6528
|
-
return UITransformer.transform(question, sources, this.config,
|
|
6877
|
+
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6529
6878
|
}
|
|
6530
|
-
if (
|
|
6531
|
-
return UITransformer.transform(
|
|
6879
|
+
if (UITransformer.isProductQueryPublic(question)) {
|
|
6880
|
+
return UITransformer.transform(
|
|
6881
|
+
question,
|
|
6882
|
+
sources,
|
|
6883
|
+
this.config,
|
|
6884
|
+
cachedSchema,
|
|
6885
|
+
{ visualizationHint: "product_browse", recommendedChart: "text", filterInStockOnly: false, wantsExplicitTable: false, isTemporal: false, isComparison: false, language: "en" }
|
|
6886
|
+
);
|
|
6887
|
+
}
|
|
6888
|
+
const isLocalProvider = this.config.llm.provider === "ollama";
|
|
6889
|
+
const disableLlmUiTransform = ((_a = this.config.llm.options) == null ? void 0 : _a.disableLlmUiTransform) === true;
|
|
6890
|
+
if (forceDeterministic || isLocalProvider || disableLlmUiTransform) {
|
|
6891
|
+
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6532
6892
|
}
|
|
6533
6893
|
try {
|
|
6534
6894
|
return await UITransformer.analyzeAndDecide(question, sources, this.llmRouter.get("fast"));
|
|
6535
6895
|
} catch (err) {
|
|
6536
6896
|
console.warn("[Pipeline] generateUiTransformation failed, using heuristic fallback:", err);
|
|
6537
|
-
return UITransformer.transform(question, sources, this.config,
|
|
6897
|
+
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6538
6898
|
}
|
|
6539
6899
|
}
|
|
6540
6900
|
applyStructuredFilters(sources, filter) {
|
|
@@ -6618,25 +6978,29 @@ ${context}`;
|
|
|
6618
6978
|
return Number.isFinite(numeric) ? numeric : null;
|
|
6619
6979
|
}
|
|
6620
6980
|
async retrieve(query, options) {
|
|
6621
|
-
var _a, _b, _c, _d, _e, _f;
|
|
6981
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
6622
6982
|
const ns = (_a = options.namespace) != null ? _a : this.config.projectId;
|
|
6623
6983
|
const topK = (_b = options.topK) != null ? _b : 5;
|
|
6624
6984
|
const cacheKey = `${ns}::${query}`;
|
|
6625
6985
|
let queryVector = this.embeddingCache.get(cacheKey);
|
|
6626
|
-
const
|
|
6986
|
+
const useGraph = this.graphDB && ((_c = this.config.rag) == null ? void 0 : _c.useGraphRetrieval);
|
|
6987
|
+
const strategy = await QueryProcessor.determineRetrievalStrategy(
|
|
6988
|
+
query,
|
|
6989
|
+
useGraph ? this.llmRouter.get("fast") : void 0
|
|
6990
|
+
);
|
|
6627
6991
|
console.debug(`[Pipeline] Determined retrieval strategy: ${strategy}`);
|
|
6628
6992
|
const [retrievedVector, graphData] = await Promise.all([
|
|
6629
6993
|
// Only embed if we need vector search (strategy is 'vector' or 'both')
|
|
6630
6994
|
strategy === "vector" || strategy === "both" ? queryVector ? Promise.resolve(queryVector) : this.embeddingProvider.embed(query, { taskType: "query" }) : Promise.resolve([]),
|
|
6631
6995
|
// Only query graph if we need graph search (strategy is 'graph' or 'both')
|
|
6632
|
-
(strategy === "graph" || strategy === "both") && this.graphDB && ((
|
|
6996
|
+
(strategy === "graph" || strategy === "both") && this.graphDB && ((_d = this.config.rag) == null ? void 0 : _d.useGraphRetrieval) ? this.graphDB.query(query) : Promise.resolve(void 0)
|
|
6633
6997
|
]);
|
|
6634
6998
|
if ((strategy === "vector" || strategy === "both") && !queryVector && retrievedVector && retrievedVector.length > 0) {
|
|
6635
6999
|
this.embeddingCache.set(cacheKey, retrievedVector);
|
|
6636
7000
|
queryVector = retrievedVector;
|
|
6637
7001
|
}
|
|
6638
|
-
const baseFilter = __spreadProps(__spreadValues({}, (
|
|
6639
|
-
const numericPredicates = QueryProcessor.extractNumericPredicates(query, (
|
|
7002
|
+
const baseFilter = __spreadProps(__spreadValues({}, (_e = options.filter) != null ? _e : {}), { queryText: query });
|
|
7003
|
+
const numericPredicates = QueryProcessor.extractNumericPredicates(query, (_f = this.config.rag) == null ? void 0 : _f.filterableFields);
|
|
6640
7004
|
if (numericPredicates.length > 0) {
|
|
6641
7005
|
baseFilter.__numericPredicates = numericPredicates;
|
|
6642
7006
|
}
|
|
@@ -6647,7 +7011,7 @@ ${context}`;
|
|
|
6647
7011
|
) : [];
|
|
6648
7012
|
const resolvedSources = [];
|
|
6649
7013
|
for (const source of sources) {
|
|
6650
|
-
const parentId = (
|
|
7014
|
+
const parentId = (_g = source.metadata) == null ? void 0 : _g.parent_id;
|
|
6651
7015
|
if (parentId) {
|
|
6652
7016
|
console.log(`[Pipeline] Multi-Vector: Found child chunk. Parent ID: ${parentId}`);
|
|
6653
7017
|
resolvedSources.push(source);
|
|
@@ -6670,10 +7034,13 @@ New Question: ${question}
|
|
|
6670
7034
|
Optimized Search Query:`;
|
|
6671
7035
|
const rewrite = await this.llmProvider.chat(
|
|
6672
7036
|
[
|
|
6673
|
-
{ role: "system", content: "You are an assistant that optimizes search queries for RAG systems." },
|
|
6674
7037
|
{ role: "user", content: prompt }
|
|
6675
7038
|
],
|
|
6676
|
-
""
|
|
7039
|
+
"",
|
|
7040
|
+
{
|
|
7041
|
+
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.",
|
|
7042
|
+
temperature: 0
|
|
7043
|
+
}
|
|
6677
7044
|
);
|
|
6678
7045
|
return rewrite.trim() || question;
|
|
6679
7046
|
}
|
|
@@ -6697,10 +7064,13 @@ ${context}
|
|
|
6697
7064
|
Suggestions:`;
|
|
6698
7065
|
const response = await this.llmProvider.chat(
|
|
6699
7066
|
[
|
|
6700
|
-
{ role: "system", content: "You are a helpful assistant that generates search suggestions." },
|
|
6701
7067
|
{ role: "user", content: prompt }
|
|
6702
7068
|
],
|
|
6703
|
-
""
|
|
7069
|
+
"",
|
|
7070
|
+
{
|
|
7071
|
+
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.",
|
|
7072
|
+
temperature: 0
|
|
7073
|
+
}
|
|
6704
7074
|
);
|
|
6705
7075
|
const match = response.match(/\[[\s\S]*\]/);
|
|
6706
7076
|
if (match) {
|
|
@@ -6885,6 +7255,30 @@ var VectorPlugin = class {
|
|
|
6885
7255
|
}
|
|
6886
7256
|
};
|
|
6887
7257
|
|
|
7258
|
+
// src/core/Retrivora.ts
|
|
7259
|
+
var Retrivora = class {
|
|
7260
|
+
constructor(config) {
|
|
7261
|
+
this.config = ConfigResolver.resolveUniversal(config);
|
|
7262
|
+
this.pipeline = new Pipeline(this.config);
|
|
7263
|
+
}
|
|
7264
|
+
async initialize() {
|
|
7265
|
+
await ConfigValidator.validateAndThrow(this.config);
|
|
7266
|
+
await this.pipeline.initialize();
|
|
7267
|
+
}
|
|
7268
|
+
async ingest(documents, namespace) {
|
|
7269
|
+
return this.pipeline.ingest(documents, namespace);
|
|
7270
|
+
}
|
|
7271
|
+
async ask(question, history = [], namespace) {
|
|
7272
|
+
return this.pipeline.ask(question, history, namespace);
|
|
7273
|
+
}
|
|
7274
|
+
askStream(question, history = [], namespace) {
|
|
7275
|
+
return this.pipeline.askStream(question, history, namespace);
|
|
7276
|
+
}
|
|
7277
|
+
getPipeline() {
|
|
7278
|
+
return this.pipeline;
|
|
7279
|
+
}
|
|
7280
|
+
};
|
|
7281
|
+
|
|
6888
7282
|
// src/config/ConfigBuilder.ts
|
|
6889
7283
|
var ConfigBuilder = class {
|
|
6890
7284
|
/**
|
|
@@ -7253,6 +7647,10 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7253
7647
|
if (!isActive) break;
|
|
7254
7648
|
if (typeof chunk === "string") {
|
|
7255
7649
|
enqueue(sseTextFrame(chunk));
|
|
7650
|
+
} else if (chunk && typeof chunk === "object" && "type" in chunk && chunk.type === "thinking") {
|
|
7651
|
+
enqueue(`data: ${JSON.stringify(chunk)}
|
|
7652
|
+
|
|
7653
|
+
`);
|
|
7256
7654
|
} else {
|
|
7257
7655
|
enqueue(sseMetaFrame(chunk));
|
|
7258
7656
|
const responseChunk = chunk;
|
|
@@ -7426,14 +7824,17 @@ function createUploadHandler(configOrPlugin) {
|
|
|
7426
7824
|
}
|
|
7427
7825
|
export {
|
|
7428
7826
|
AnthropicProvider,
|
|
7827
|
+
AuthenticationException,
|
|
7429
7828
|
BaseVectorProvider,
|
|
7430
7829
|
BatchProcessor,
|
|
7431
7830
|
ChromaDBProvider,
|
|
7432
7831
|
ConfigBuilder,
|
|
7433
7832
|
ConfigResolver,
|
|
7434
7833
|
ConfigValidator,
|
|
7834
|
+
ConfigurationException,
|
|
7435
7835
|
DocumentChunker,
|
|
7436
7836
|
DocumentParser,
|
|
7837
|
+
EmbeddingFailedException,
|
|
7437
7838
|
EmbeddingStrategy,
|
|
7438
7839
|
EmbeddingStrategyResolver,
|
|
7439
7840
|
LLMFactory,
|
|
@@ -7448,9 +7849,14 @@ export {
|
|
|
7448
7849
|
Pipeline,
|
|
7449
7850
|
PostgreSQLProvider,
|
|
7450
7851
|
ProviderHealthCheck,
|
|
7852
|
+
ProviderNotFoundException,
|
|
7451
7853
|
ProviderRegistry,
|
|
7452
7854
|
QdrantProvider,
|
|
7855
|
+
RateLimitException,
|
|
7453
7856
|
RedisProvider,
|
|
7857
|
+
RetrievalException,
|
|
7858
|
+
Retrivora,
|
|
7859
|
+
RetrivoraError,
|
|
7454
7860
|
UniversalLLMAdapter,
|
|
7455
7861
|
UniversalVectorProvider,
|
|
7456
7862
|
VECTOR_PROFILES,
|