@devilsdev/rag-pipeline-utils 2.4.5 → 2.5.0
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/.ragrc.schema.json +83 -192
- package/CHANGELOG.md +345 -0
- package/README.md +418 -117
- package/SECURITY.md +5 -5
- package/dist/experimental.cjs +2 -0
- package/dist/experimental.d.ts +1 -0
- package/dist/experimental.mjs +5 -0
- package/dist/index.cjs +4992 -1242
- package/dist/index.d.ts +80 -2
- package/dist/index.mjs +1 -1
- package/dist/types/agentic/agentic-pipeline.d.ts +103 -0
- package/dist/types/agentic/iterative-retriever.d.ts +85 -0
- package/dist/types/agentic/query-planner.d.ts +145 -0
- package/dist/types/agentic/self-critique.d.ts +45 -0
- package/dist/types/ai/adaptive-retrieval.d.ts +44 -0
- package/dist/types/ai/federation/federated-learning-coordinator.d.ts +62 -0
- package/dist/types/ai/multimodal-processing.d.ts +32 -0
- package/dist/types/ai/multimodal.d.ts +39 -0
- package/dist/types/ai/retrieval-engine.d.ts +37 -0
- package/dist/types/ai/training/model-training-orchestrator.d.ts +31 -0
- package/dist/types/chunking/chunking-engine.d.ts +70 -0
- package/dist/types/chunking/strategies/fixed-size.d.ts +17 -0
- package/dist/types/chunking/strategies/recursive.d.ts +20 -0
- package/dist/types/chunking/strategies/semantic.d.ts +19 -0
- package/dist/types/chunking/strategies/sentence.d.ts +13 -0
- package/dist/types/chunking/strategies/structure-aware.d.ts +19 -0
- package/dist/types/citation/citation-tracker.d.ts +64 -0
- package/dist/types/citation/hallucination-detector.d.ts +40 -0
- package/dist/types/citation/source-mapper.d.ts +37 -0
- package/dist/types/connectors/anthropic-connector.d.ts +92 -0
- package/dist/types/connectors/base-connector.d.ts +87 -0
- package/dist/types/connectors/cohere-connector.d.ts +89 -0
- package/dist/types/connectors/connector-utils.d.ts +110 -0
- package/dist/types/connectors/local-embedder.d.ts +86 -0
- package/dist/types/connectors/memory-retriever.d.ts +91 -0
- package/dist/types/connectors/ollama-connector.d.ts +110 -0
- package/dist/types/connectors/openai-connector.d.ts +114 -0
- package/dist/types/connectors/rag-prompt.d.ts +40 -0
- package/dist/types/cost/cost-calculator.d.ts +152 -0
- package/dist/types/cost/cost-tracker.d.ts +126 -0
- package/dist/types/cost/token-budget.d.ts +110 -0
- package/dist/types/dag/core/error-context.d.ts +239 -0
- package/dist/types/dag/core/execution-scheduler.d.ts +191 -0
- package/dist/types/dag/core/topology-validation.d.ts +226 -0
- package/dist/types/dag/dag-engine.d.ts +156 -0
- package/dist/types/dag/dag-node.d.ts +37 -0
- package/dist/types/dashboard/dashboard-generator.d.ts +127 -0
- package/dist/types/dashboard/metrics-aggregator.d.ts +218 -0
- package/dist/types/debug/execution-tracer.d.ts +57 -0
- package/dist/types/debug/trace-inspector.d.ts +31 -0
- package/dist/types/ecosystem/plugin-certification.d.ts +169 -0
- package/dist/types/enterprise/data-governance.d.ts +203 -0
- package/dist/types/enterprise/multi-tenancy.d.ts +137 -0
- package/dist/types/enterprise/sso-integration.d.ts +420 -0
- package/dist/types/evaluate/context-metrics.d.ts +55 -0
- package/dist/types/evaluate/faithfulness.d.ts +41 -0
- package/dist/types/evaluate/groundedness.d.ts +60 -0
- package/dist/types/evaluate/pipeline-evaluator.d.ts +88 -0
- package/dist/types/evaluate/relevance.d.ts +21 -0
- package/dist/types/evaluate/scoring.d.ts +123 -0
- package/dist/types/experimental.d.ts +15 -0
- package/dist/types/graph/entity-extractor.d.ts +84 -0
- package/dist/types/graph/graph-index.d.ts +49 -0
- package/dist/types/graph/graph-retriever.d.ts +81 -0
- package/dist/types/graph/knowledge-graph.d.ts +129 -0
- package/dist/types/guardrails/guardrails-pipeline.d.ts +63 -0
- package/dist/types/guardrails/injection-detector.d.ts +47 -0
- package/dist/types/guardrails/post-generation-guard.d.ts +61 -0
- package/dist/types/guardrails/pre-retrieval-guard.d.ts +64 -0
- package/dist/types/guardrails/retrieval-guard.d.ts +57 -0
- package/dist/types/mcp/mcp-server.d.ts +85 -0
- package/dist/types/mcp/mcp-tool-builder.d.ts +55 -0
- package/dist/types/reranker/cascade-reranker.d.ts +40 -0
- package/dist/types/reranker/embedding-reranker.d.ts +77 -0
- package/dist/types/reranker/scoring-reranker.d.ts +41 -0
- package/dist/types/retrieval/bm25-search.d.ts +43 -0
- package/dist/types/retrieval/file-vector-store.d.ts +87 -0
- package/dist/types/retrieval/hybrid-retriever.d.ts +35 -0
- package/dist/types/retrieval/rank-fusion.d.ts +10 -0
- package/dist/types/security/jwt-config.d.ts +80 -0
- package/dist/types/security/jwt-validator.d.ts +195 -0
- package/dist/types/security/plugin-sandbox.d.ts +158 -0
- package/dist/types/security/plugin-signature-verifier.d.ts +139 -0
- package/dist/types/security/validator.d.ts +5 -0
- package/dist/types/streaming/embedding-stream.d.ts +65 -0
- package/dist/types/streaming/sse-adapter.d.ts +59 -0
- package/dist/types/streaming/stream-router.d.ts +88 -0
- package/dist/types/streaming/streaming-embedder.d.ts +99 -0
- package/dist/types/streaming/websocket-adapter.d.ts +71 -0
- package/dist/types/templates/scaffold.d.ts +55 -0
- package/dist/types/templates/template-registry.d.ts +63 -0
- package/dist/types/utils/embed-query.d.ts +20 -0
- package/dist/types/utils/logger.d.ts +50 -0
- package/dist/types/utils/rate-limiter.d.ts +66 -0
- package/dist/types/utils/retry.d.ts +27 -0
- package/dist/types/utils/run-abort.d.ts +34 -0
- package/dist/types/utils/secure-logging.d.ts +51 -0
- package/dist/types/utils/structured-logger.d.ts +126 -0
- package/package.json +53 -29
- package/src/agentic/agentic-pipeline.js +75 -7
- package/src/agentic/iterative-retriever.js +47 -10
- package/src/agentic/query-planner.js +329 -78
- package/src/citation/citation-tracker.js +6 -4
- package/src/citation/hallucination-detector.js +2 -2
- package/src/citation/source-mapper.js +15 -28
- package/src/cli/commands/ai.js +101 -0
- package/src/cli/commands/plugin-hub/event-handlers.js +6 -0
- package/src/cli/commands/plugin-hub/hub-commands.js +0 -74
- package/src/cli/commands/plugin-hub/local-commands.js +143 -0
- package/src/cli/commands/plugin-hub.js +96 -36
- package/src/cli/diagnostics/config-checker.js +76 -63
- package/src/cli/diagnostics/environment-checker.js +62 -31
- package/src/cli/diagnostics/plugin-checker.js +36 -89
- package/src/cli/doctor-command.js +39 -5
- package/src/cli/enhanced-cli-commands.js +72 -217
- package/src/cli/handlers/ai-handler.js +364 -0
- package/src/cli/handlers/diagnostics-handler.js +78 -31
- package/src/cli/handlers/ingest-handler.js +28 -22
- package/src/cli/handlers/init-handler.js +148 -25
- package/src/cli/handlers/query-handler.js +41 -26
- package/src/cli/handlers/run-handler.js +16 -167
- package/src/cli/handlers/serve-handler.js +60 -0
- package/src/cli/services/bench-stats.js +54 -0
- package/src/cli/services/benchmark.js +161 -0
- package/src/cli/services/feedback.js +155 -0
- package/src/cli/services/rag-service.js +322 -0
- package/src/cli/shared/cli-utils.js +24 -7
- package/src/cli/shared/config-context.js +21 -0
- package/src/cli/wizard/config-builder.js +81 -0
- package/src/cli/wizard/init-wizard.js +617 -0
- package/src/config/component-factory.js +125 -0
- package/src/config/load-config.js +29 -10
- package/src/config/load-plugin-config.js +46 -2
- package/src/connectors/anthropic-connector.js +93 -55
- package/src/connectors/base-connector.js +74 -19
- package/src/connectors/cohere-connector.js +88 -32
- package/src/connectors/connector-utils.js +302 -0
- package/src/connectors/local-embedder.js +43 -5
- package/src/connectors/memory-retriever.js +108 -15
- package/src/connectors/ollama-connector.js +83 -49
- package/src/connectors/openai-connector.js +108 -44
- package/src/connectors/rag-prompt.js +88 -0
- package/src/core/create-pipeline.js +209 -60
- package/src/core/plugin-registry.js +87 -11
- package/src/cost/cost-calculator.js +205 -32
- package/src/dev/dev-server.js +166 -11
- package/src/dev/hot-reload.js +40 -1
- package/src/ecosystem/plugin-checks.js +181 -0
- package/src/ecosystem/plugin-hub.js +50 -125
- package/src/ecosystem/plugin-installer.js +298 -0
- package/src/ecosystem/plugin-probe.js +127 -0
- package/src/ecosystem/plugin-scanner.js +185 -0
- package/src/ecosystem/tar-extract.js +114 -0
- package/src/enterprise/audit-logging.js +158 -29
- package/src/enterprise/sso-integration.js +715 -228
- package/src/evaluate/context-metrics.js +28 -16
- package/src/evaluate/evaluator.js +3 -3
- package/src/evaluate/faithfulness.js +18 -14
- package/src/evaluate/groundedness.js +43 -12
- package/src/evaluate/pipeline-evaluator.js +35 -8
- package/src/evaluate/scoring.js +251 -3
- package/src/experimental.js +71 -0
- package/src/guardrails/guardrails-pipeline.js +69 -7
- package/src/guardrails/injection-detector.js +283 -0
- package/src/guardrails/post-generation-guard.js +19 -0
- package/src/guardrails/pre-retrieval-guard.js +36 -36
- package/src/guardrails/retrieval-guard.js +58 -8
- package/src/index.js +36 -1
- package/src/loader/document-reader.js +91 -0
- package/src/reranker/cascade-reranker.js +3 -0
- package/src/reranker/embedding-reranker.js +136 -21
- package/src/reranker/llm-reranker.js +79 -12
- package/src/reranker/scoring-reranker.js +3 -0
- package/src/retrieval/bm25-search.js +12 -6
- package/src/retrieval/file-vector-store.js +212 -0
- package/src/retrieval/hybrid-retriever.js +22 -19
- package/src/security/jwt-config.js +13 -2
- package/src/security/jwt-validator.js +134 -30
- package/src/security/plugin-sandbox.js +18 -1
- package/src/security/plugin-signature-verifier.js +245 -70
- package/src/utils/deprecate.js +69 -0
- package/src/utils/embed-query.js +33 -0
- package/src/utils/input-sanitizer.js +19 -4
- package/src/utils/logger.js +34 -4
- package/src/utils/run-abort.js +102 -0
- package/src/ai/federated-learning.js +0 -211
- package/src/ai/federation.js +0 -71
- package/src/ai/index.js +0 -22
- package/src/ai/model-trainer.js +0 -217
- package/src/ai/model-training.js +0 -202
- package/src/ai/multimodal/multi-modal-processor.js +0 -345
- package/src/ai/orchestrator.js +0 -65
- package/src/ai/retrieval/adaptive-retrieval-engine.js +0 -398
- package/src/cli/commands/ai-ml/adaptive-commands.js +0 -178
- package/src/cli/commands/ai-ml/federated-commands.js +0 -207
- package/src/cli/commands/ai-ml/index.js +0 -17
- package/src/cli/commands/ai-ml/multimodal-commands.js +0 -187
- package/src/cli/commands/ai-ml/shared.js +0 -51
- package/src/cli/commands/ai-ml/training-commands.js +0 -228
- package/src/cli/commands/ai-ml.js +0 -386
- package/src/cli/commands/docs.js +0 -228
- package/src/cli/commands/dx.js +0 -538
- package/src/cli/commands/wizard.js +0 -627
- package/src/cli/input-sanitization-middleware.js +0 -356
- package/src/cli/interactive-wizard.js +0 -373
- package/src/cli/templates/development.template.json +0 -64
- package/src/cli/templates/minimal.template.json +0 -33
- package/src/cli/templates/production.template.json +0 -104
- package/src/cli/templates/testing.template.json +0 -45
- package/src/cli/wizard/configuration.js +0 -148
- package/src/cli/wizard/observability.js +0 -79
- package/src/cli/wizard/performance.js +0 -76
- package/src/cli/wizard/plugin-selection.js +0 -297
- package/src/cli/wizard/preview-save.js +0 -172
- package/src/cli/wizard/project-setup.js +0 -66
- package/src/core/pipeline-factory.js +0 -59
- package/src/dag/enhanced-dag-engine.js +0 -894
- package/src/dx/index.js +0 -40
- package/src/dx/integration-templates.js +0 -662
- package/src/dx/performance-profiler.js +0 -968
- package/src/dx/realtime-debugger.js +0 -755
- package/src/dx/visual-pipeline-builder.js +0 -578
- package/src/ingest.js +0 -59
- package/src/pipeline/pipeline.js +0 -18
- package/src/query.js +0 -117
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { BaseConnector } = require('./base-connector');
|
|
4
|
+
const { throwIfAborted } = require('./connector-utils');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Default configuration for the in-memory retriever.
|
|
@@ -8,32 +9,86 @@ const { BaseConnector } = require('./base-connector');
|
|
|
8
9
|
*/
|
|
9
10
|
const DEFAULT_CONFIG = {
|
|
10
11
|
maxDocuments: 100000,
|
|
12
|
+
// 'error' rejects a store() that would exceed maxDocuments; 'fifo' evicts
|
|
13
|
+
// the oldest documents (insertion order) to make room.
|
|
14
|
+
eviction: 'error',
|
|
11
15
|
};
|
|
12
16
|
|
|
13
17
|
/**
|
|
14
18
|
* In-memory vector store with cosine similarity retrieval.
|
|
15
19
|
* Stores document vectors and retrieves the most similar ones to a query vector.
|
|
20
|
+
* All vectors in one store must have the same dimension.
|
|
16
21
|
* @extends BaseConnector
|
|
17
22
|
*/
|
|
18
23
|
class MemoryRetriever extends BaseConnector {
|
|
19
24
|
/**
|
|
20
25
|
* @param {Object} options
|
|
21
26
|
* @param {number} [options.maxDocuments=100000] - Maximum number of documents to store
|
|
27
|
+
* @param {'error'|'fifo'} [options.eviction='error'] - What to do when a store()
|
|
28
|
+
* would exceed maxDocuments: throw (default) or evict the oldest documents
|
|
22
29
|
*/
|
|
23
30
|
constructor(options = {}) {
|
|
24
31
|
super({ name: 'memory-retriever', ...options });
|
|
25
32
|
this.config = { ...DEFAULT_CONFIG, ...options };
|
|
33
|
+
if (!['error', 'fifo'].includes(this.config.eviction)) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`MemoryRetriever: unknown eviction "${this.config.eviction}" (use "error" or "fifo")`,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
26
38
|
/** @type {Map<string, { vector: number[], metadata?: Object, content?: string }>} */
|
|
27
39
|
this.documents = new Map();
|
|
40
|
+
/** @type {number|null} Vector dimension, fixed by the first stored vector */
|
|
41
|
+
this.dimensions = null;
|
|
28
42
|
this.connected = true;
|
|
29
43
|
}
|
|
30
44
|
|
|
31
45
|
/**
|
|
32
|
-
* Store one or more vector documents.
|
|
46
|
+
* Store one or more vector documents. The batch is validated before
|
|
47
|
+
* anything is inserted, so a rejected call leaves the store unchanged.
|
|
48
|
+
*
|
|
33
49
|
* @param {Array<{ id: string, vector: number[], metadata?: Object, content?: string }>} vectors
|
|
34
50
|
* @returns {Promise<void>}
|
|
51
|
+
* @throws {Error} When a vector's dimension differs from the store's, or
|
|
52
|
+
* (eviction 'error') when the store would exceed maxDocuments
|
|
35
53
|
*/
|
|
36
54
|
async store(vectors) {
|
|
55
|
+
let dimensions = this.dimensions;
|
|
56
|
+
const newIds = new Set();
|
|
57
|
+
for (const doc of vectors) {
|
|
58
|
+
const length = doc && doc.vector ? doc.vector.length : undefined;
|
|
59
|
+
if (typeof length !== 'number') {
|
|
60
|
+
throw new Error(
|
|
61
|
+
`MemoryRetriever.store(): document "${doc && doc.id}" has no vector`,
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
if (dimensions === null) {
|
|
65
|
+
dimensions = length;
|
|
66
|
+
} else if (length !== dimensions) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`MemoryRetriever.store(): document "${doc.id}" has ${length} dimensions ` +
|
|
69
|
+
`but the store holds ${dimensions}-dimension vectors. Use the same embedder for all documents.`,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
if (!this.documents.has(doc.id)) newIds.add(doc.id);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const { maxDocuments, eviction } = this.config;
|
|
76
|
+
const projected = this.documents.size + newIds.size;
|
|
77
|
+
if (projected > maxDocuments) {
|
|
78
|
+
if (eviction !== 'fifo') {
|
|
79
|
+
throw new Error(
|
|
80
|
+
`MemoryRetriever.store(): storing ${newIds.size} new document(s) would bring the ` +
|
|
81
|
+
`total to ${projected}, exceeding maxDocuments (${maxDocuments}). Raise ` +
|
|
82
|
+
'maxDocuments, call clear(), or construct with { eviction: \'fifo\' }.',
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
if (newIds.size > maxDocuments) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
`MemoryRetriever.store(): batch of ${newIds.size} new documents exceeds maxDocuments (${maxDocuments})`,
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
37
92
|
for (const doc of vectors) {
|
|
38
93
|
this.documents.set(doc.id, {
|
|
39
94
|
vector: doc.vector,
|
|
@@ -41,11 +96,19 @@ class MemoryRetriever extends BaseConnector {
|
|
|
41
96
|
content: doc.content || '',
|
|
42
97
|
});
|
|
43
98
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
99
|
+
if (vectors.length > 0) this.dimensions = dimensions;
|
|
100
|
+
|
|
101
|
+
let evicted = 0;
|
|
102
|
+
if (this.documents.size > maxDocuments) {
|
|
103
|
+
// FIFO eviction: Map iteration follows insertion order. Never evict a
|
|
104
|
+
// document from the current batch.
|
|
105
|
+
for (const id of this.documents.keys()) {
|
|
106
|
+
if (this.documents.size <= maxDocuments) break;
|
|
107
|
+
if (newIds.has(id)) continue;
|
|
108
|
+
this.documents.delete(id);
|
|
109
|
+
evicted++;
|
|
110
|
+
}
|
|
111
|
+
this.emit('evicted', { count: evicted, total: this.documents.size });
|
|
49
112
|
}
|
|
50
113
|
|
|
51
114
|
this.emit('stored', { count: vectors.length, total: this.documents.size });
|
|
@@ -53,20 +116,42 @@ class MemoryRetriever extends BaseConnector {
|
|
|
53
116
|
|
|
54
117
|
/**
|
|
55
118
|
* Retrieve the top-k most similar documents to a query vector.
|
|
56
|
-
* @param {number[]|{ query?: string, queryVector: number[], topK?: number }} queryOrObj
|
|
57
|
-
* Either a raw vector array or an object with queryVector
|
|
119
|
+
* @param {number[]|{ query?: string, queryVector: number[], topK?: number, signal?: AbortSignal }} queryOrObj
|
|
120
|
+
* Either a raw vector array or an object with queryVector, optional topK
|
|
121
|
+
* and optional AbortSignal.
|
|
58
122
|
* @param {number} [k=10] - Number of results to return (used when queryOrObj is an array)
|
|
59
123
|
* @returns {Promise<Array<{ id: string, score: number, metadata: Object, content: string }>>}
|
|
124
|
+
* @throws {Error} When the query vector's dimension differs from the stored vectors
|
|
60
125
|
*/
|
|
61
126
|
async retrieve(queryOrObj, k = 10) {
|
|
62
127
|
let queryVector;
|
|
63
128
|
let topK = k;
|
|
129
|
+
let signal;
|
|
64
130
|
|
|
65
131
|
if (Array.isArray(queryOrObj)) {
|
|
66
132
|
queryVector = queryOrObj;
|
|
67
133
|
} else {
|
|
68
|
-
queryVector = queryOrObj
|
|
69
|
-
topK = queryOrObj
|
|
134
|
+
queryVector = queryOrObj?.queryVector;
|
|
135
|
+
topK = queryOrObj?.topK || k;
|
|
136
|
+
signal = queryOrObj?.signal;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
throwIfAborted(signal);
|
|
140
|
+
|
|
141
|
+
if (!Array.isArray(queryVector) && !ArrayBuffer.isView(queryVector)) {
|
|
142
|
+
throw new Error(
|
|
143
|
+
'MemoryRetriever.retrieve(): queryVector is required. Pass an ' +
|
|
144
|
+
'`embedder` to createRagPipeline or supply `queryVector` to run().',
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (this.dimensions !== null && this.documents.size > 0) {
|
|
149
|
+
if (queryVector.length !== this.dimensions) {
|
|
150
|
+
throw new Error(
|
|
151
|
+
`Query vector has ${queryVector.length} dimensions but the store holds ` +
|
|
152
|
+
`${this.dimensions}-dimension vectors. Use the same embedder for queries and documents.`,
|
|
153
|
+
);
|
|
154
|
+
}
|
|
70
155
|
}
|
|
71
156
|
|
|
72
157
|
const results = [];
|
|
@@ -83,23 +168,29 @@ class MemoryRetriever extends BaseConnector {
|
|
|
83
168
|
|
|
84
169
|
results.sort((a, b) => b.score - a.score);
|
|
85
170
|
|
|
171
|
+
throwIfAborted(signal);
|
|
86
172
|
return results.slice(0, topK);
|
|
87
173
|
}
|
|
88
174
|
|
|
89
175
|
/**
|
|
90
|
-
* Compute cosine similarity between two vectors.
|
|
176
|
+
* Compute cosine similarity between two vectors of equal length.
|
|
91
177
|
* @param {number[]} a - First vector
|
|
92
178
|
* @param {number[]} b - Second vector
|
|
93
179
|
* @returns {number} Cosine similarity in the range [-1, 1], or 0 for zero vectors
|
|
180
|
+
* @throws {Error} When the vectors have different lengths
|
|
94
181
|
* @private
|
|
95
182
|
*/
|
|
96
183
|
_cosineSimilarity(a, b) {
|
|
97
|
-
|
|
184
|
+
if (a.length !== b.length) {
|
|
185
|
+
throw new Error(
|
|
186
|
+
`Cannot compare vectors of different dimensions (${a.length} vs ${b.length})`,
|
|
187
|
+
);
|
|
188
|
+
}
|
|
98
189
|
let dot = 0;
|
|
99
190
|
let magA = 0;
|
|
100
191
|
let magB = 0;
|
|
101
192
|
|
|
102
|
-
for (let i = 0; i <
|
|
193
|
+
for (let i = 0; i < a.length; i++) {
|
|
103
194
|
dot += a[i] * b[i];
|
|
104
195
|
magA += a[i] * a[i];
|
|
105
196
|
magB += b[i] * b[i];
|
|
@@ -112,21 +203,23 @@ class MemoryRetriever extends BaseConnector {
|
|
|
112
203
|
}
|
|
113
204
|
|
|
114
205
|
/**
|
|
115
|
-
* Remove all stored documents.
|
|
206
|
+
* Remove all stored documents and reset the vector dimension.
|
|
116
207
|
* @returns {Promise<void>}
|
|
117
208
|
*/
|
|
118
209
|
async clear() {
|
|
119
210
|
this.documents.clear();
|
|
211
|
+
this.dimensions = null;
|
|
120
212
|
}
|
|
121
213
|
|
|
122
214
|
/**
|
|
123
215
|
* Get statistics about the store.
|
|
124
|
-
* @returns {{ documentCount: number, maxDocuments: number }}
|
|
216
|
+
* @returns {{ documentCount: number, maxDocuments: number, dimensions: number|null }}
|
|
125
217
|
*/
|
|
126
218
|
getStats() {
|
|
127
219
|
return {
|
|
128
220
|
documentCount: this.documents.size,
|
|
129
221
|
maxDocuments: this.config.maxDocuments,
|
|
222
|
+
dimensions: this.dimensions,
|
|
130
223
|
};
|
|
131
224
|
}
|
|
132
225
|
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
const axios = require('axios');
|
|
4
4
|
const { BaseConnector } = require('./base-connector');
|
|
5
|
+
const {
|
|
6
|
+
raceAbort,
|
|
7
|
+
signalOptions,
|
|
8
|
+
throwIfAborted,
|
|
9
|
+
} = require('./connector-utils');
|
|
10
|
+
const { buildRagPrompt } = require('./rag-prompt');
|
|
5
11
|
|
|
6
12
|
/**
|
|
7
13
|
* Default configuration for the Ollama connector.
|
|
@@ -13,11 +19,14 @@ const DEFAULT_CONFIG = {
|
|
|
13
19
|
embeddingModel: 'nomic-embed-text',
|
|
14
20
|
timeout: 60000,
|
|
15
21
|
temperature: 0.7,
|
|
22
|
+
maxRetries: 3,
|
|
23
|
+
retryDelay: 1000,
|
|
16
24
|
};
|
|
17
25
|
|
|
18
26
|
/**
|
|
19
27
|
* Connector for Ollama local LLM server.
|
|
20
28
|
* Supports text generation (sync and streaming) and embeddings.
|
|
29
|
+
* Ollama needs no API key.
|
|
21
30
|
* @extends BaseConnector
|
|
22
31
|
*/
|
|
23
32
|
class OllamaConnector extends BaseConnector {
|
|
@@ -28,6 +37,9 @@ class OllamaConnector extends BaseConnector {
|
|
|
28
37
|
* @param {string} [options.embeddingModel='nomic-embed-text'] - Default embedding model
|
|
29
38
|
* @param {number} [options.timeout=60000] - Request timeout in ms
|
|
30
39
|
* @param {number} [options.temperature=0.7] - Generation temperature
|
|
40
|
+
* @param {number} [options.maxRetries=3] - Retries for transient failures
|
|
41
|
+
* @param {number} [options.retryDelay=1000] - Base backoff delay in ms
|
|
42
|
+
* @param {string} [options.systemPrompt] - System prompt used when RAG context is supplied
|
|
31
43
|
*/
|
|
32
44
|
constructor(options = {}) {
|
|
33
45
|
super({ name: 'ollama', ...options });
|
|
@@ -67,6 +79,46 @@ class OllamaConnector extends BaseConnector {
|
|
|
67
79
|
}
|
|
68
80
|
}
|
|
69
81
|
|
|
82
|
+
/**
|
|
83
|
+
* POST with the connector's retry policy and cancellation.
|
|
84
|
+
* @private
|
|
85
|
+
*/
|
|
86
|
+
_post(path, body, signal) {
|
|
87
|
+
throwIfAborted(signal);
|
|
88
|
+
return this.withRetry(
|
|
89
|
+
async () => {
|
|
90
|
+
const response = await this.client.post(
|
|
91
|
+
path,
|
|
92
|
+
body,
|
|
93
|
+
signal ? { signal } : undefined,
|
|
94
|
+
);
|
|
95
|
+
return response.data;
|
|
96
|
+
},
|
|
97
|
+
this.config.maxRetries,
|
|
98
|
+
this.config.retryDelay,
|
|
99
|
+
{ signal },
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Build the /api/generate body. Retrieved context goes into the prompt as
|
|
105
|
+
* delimited, untrusted reference data; instructions go in `system`.
|
|
106
|
+
* @private
|
|
107
|
+
*/
|
|
108
|
+
_buildBody(query, context, options, stream) {
|
|
109
|
+
const prompt = buildRagPrompt(query, context, {
|
|
110
|
+
systemPrompt: this.config.systemPrompt,
|
|
111
|
+
});
|
|
112
|
+
const body = {
|
|
113
|
+
model: options.model || this.config.model,
|
|
114
|
+
prompt: prompt.user,
|
|
115
|
+
stream,
|
|
116
|
+
options: { temperature: options.temperature ?? this.config.temperature },
|
|
117
|
+
};
|
|
118
|
+
if (prompt.system) body.system = prompt.system;
|
|
119
|
+
return body;
|
|
120
|
+
}
|
|
121
|
+
|
|
70
122
|
/**
|
|
71
123
|
* Generate a response for the given query with optional context documents.
|
|
72
124
|
* @param {string} query - The user query
|
|
@@ -74,24 +126,13 @@ class OllamaConnector extends BaseConnector {
|
|
|
74
126
|
* @param {Object} [options={}] - Override options
|
|
75
127
|
* @param {string} [options.model] - Override the generation model
|
|
76
128
|
* @param {number} [options.temperature] - Override temperature
|
|
129
|
+
* @param {AbortSignal} [options.signal] - Cancels the request
|
|
77
130
|
* @returns {Promise<string>} Generated response text
|
|
78
131
|
*/
|
|
79
132
|
async generate(query, context = [], options = {}) {
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const result = await this.withRetry(async () => {
|
|
85
|
-
const response = await this.client.post('/api/generate', {
|
|
86
|
-
model,
|
|
87
|
-
prompt,
|
|
88
|
-
stream: false,
|
|
89
|
-
options: { temperature },
|
|
90
|
-
});
|
|
91
|
-
return response.data.response;
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
return result;
|
|
133
|
+
const body = this._buildBody(query, context, options, false);
|
|
134
|
+
const data = await this._post('/api/generate', body, options.signal);
|
|
135
|
+
return data.response;
|
|
95
136
|
}
|
|
96
137
|
|
|
97
138
|
/**
|
|
@@ -101,31 +142,31 @@ class OllamaConnector extends BaseConnector {
|
|
|
101
142
|
* @param {Object} [options={}] - Override options
|
|
102
143
|
* @param {string} [options.model] - Override the generation model
|
|
103
144
|
* @param {number} [options.temperature] - Override temperature
|
|
145
|
+
* @param {AbortSignal} [options.signal] - Cancels the stream
|
|
104
146
|
* @yields {{ token: string, done: boolean }}
|
|
105
147
|
*/
|
|
106
148
|
async *generateStream(query, context = [], options = {}) {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
const
|
|
149
|
+
const { signal } = options;
|
|
150
|
+
throwIfAborted(signal);
|
|
151
|
+
const body = this._buildBody(query, context, options, true);
|
|
110
152
|
|
|
111
153
|
let response;
|
|
112
154
|
try {
|
|
113
|
-
response = await
|
|
114
|
-
'/api/generate',
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
options: { temperature },
|
|
120
|
-
},
|
|
121
|
-
{ responseType: 'stream' },
|
|
155
|
+
response = await raceAbort(
|
|
156
|
+
this.client.post('/api/generate', body, {
|
|
157
|
+
responseType: 'stream',
|
|
158
|
+
...signalOptions(signal),
|
|
159
|
+
}),
|
|
160
|
+
signal,
|
|
122
161
|
);
|
|
123
162
|
} catch (err) {
|
|
163
|
+
if (err && err.name === 'AbortError') throw err;
|
|
124
164
|
throw new Error(`Ollama streaming request failed: ${err.message}`);
|
|
125
165
|
}
|
|
126
166
|
|
|
127
167
|
let buffer = '';
|
|
128
168
|
for await (const chunk of response.data) {
|
|
169
|
+
throwIfAborted(signal);
|
|
129
170
|
buffer += chunk.toString();
|
|
130
171
|
const lines = buffer.split('\n');
|
|
131
172
|
// Keep the last potentially incomplete line in the buffer
|
|
@@ -157,48 +198,41 @@ class OllamaConnector extends BaseConnector {
|
|
|
157
198
|
/**
|
|
158
199
|
* Generate an embedding vector for the given text.
|
|
159
200
|
* @param {string} text - Text to embed
|
|
201
|
+
* @param {Object} [options={}]
|
|
202
|
+
* @param {AbortSignal} [options.signal] - Cancels the request
|
|
160
203
|
* @returns {Promise<number[]>} Embedding vector
|
|
161
204
|
*/
|
|
162
|
-
async embed(text) {
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
return result;
|
|
205
|
+
async embed(text, options = {}) {
|
|
206
|
+
const data = await this._post(
|
|
207
|
+
'/api/embeddings',
|
|
208
|
+
{ model: this.config.embeddingModel, prompt: text },
|
|
209
|
+
options.signal,
|
|
210
|
+
);
|
|
211
|
+
return data.embedding;
|
|
172
212
|
}
|
|
173
213
|
|
|
174
214
|
/**
|
|
175
215
|
* Generate an embedding vector for a query string.
|
|
176
216
|
* Alias for {@link embed}.
|
|
177
217
|
* @param {string} query - Query text to embed
|
|
218
|
+
* @param {Object} [options={}] - Same as embed()
|
|
178
219
|
* @returns {Promise<number[]>} Embedding vector
|
|
179
220
|
*/
|
|
180
|
-
async embedQuery(query) {
|
|
181
|
-
return this.embed(query);
|
|
221
|
+
async embedQuery(query, options = {}) {
|
|
222
|
+
return this.embed(query, options);
|
|
182
223
|
}
|
|
183
224
|
|
|
184
225
|
/**
|
|
185
226
|
* Build a prompt string incorporating context documents.
|
|
227
|
+
* Kept for backward compatibility; context is delimited and labelled as
|
|
228
|
+
* untrusted reference data.
|
|
186
229
|
* @param {string} query - The user query
|
|
187
230
|
* @param {Array<Object|string>} context - Context documents
|
|
188
231
|
* @returns {string} Formatted prompt
|
|
189
232
|
* @private
|
|
190
233
|
*/
|
|
191
234
|
_buildPrompt(query, context) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const contextText = context
|
|
195
|
-
.map((doc) => {
|
|
196
|
-
const text = doc.content || doc.text || String(doc);
|
|
197
|
-
return text;
|
|
198
|
-
})
|
|
199
|
-
.join('\n\n');
|
|
200
|
-
|
|
201
|
-
return `Context:\n${contextText}\n\nQuestion: ${query}\n\nAnswer:`;
|
|
235
|
+
return buildRagPrompt(query, context).user;
|
|
202
236
|
}
|
|
203
237
|
}
|
|
204
238
|
|