@devilsdev/rag-pipeline-utils 1.0.0 → 2.0.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/.codecov.yml +21 -0
- package/.dockerignore +14 -14
- package/.eslintignore +5 -0
- package/.eslintrc.json +21 -0
- package/.github/workflows/ci.yml +64 -42
- package/.husky/pre-commit +5 -0
- package/CHANGELOG.md +46 -0
- package/Dockerfile +22 -22
- package/LICENSE +674 -674
- package/README.md +117 -116
- package/__tests__/fixtures/.ragrc.json +8 -0
- package/__tests__/fixtures/invalid-ragrc.json +4 -0
- package/__tests__/fixtures/sample-eval-dataset.json +14 -14
- package/__tests__/fixtures/sample.pdf +1 -0
- package/__tests__/fixtures/src/mocks/openai-embedder.js +16 -0
- package/__tests__/fixtures/src/mocks/openai-llm.js +9 -0
- package/__tests__/fixtures/src/mocks/pdf-loader.js +17 -0
- package/__tests__/fixtures/src/mocks/pinecone-retriever.js +26 -0
- package/__tests__/fixtures/valid-ragrc.json +16 -0
- package/__tests__/integration/cli/config-flow.test.js +98 -44
- package/__tests__/integration/config/load-config.test.js +67 -52
- package/__tests__/unit/config/validate-schema.test.js +121 -0
- package/__tests__/unit/core/plugin-registry.test.js +55 -55
- package/__tests__/unit/reranker/llm-reranker.test.js +18 -42
- package/__tests__/unit/reranker/reranker.enriched.test.js +19 -0
- package/__tests__/unit/reranker/reranker.fallback.test.js +15 -0
- package/__tests__/unit/reranker/reranker.snapshot.test.js +15 -17
- package/__tests__/unit/reranker/reranker.structured-output.test.js +17 -0
- package/bin/cli.js +62 -168
- package/docs-site/docs/Architecture.md +76 -76
- package/docs-site/docs/CLI.md +69 -69
- package/docs-site/docs/Evaluation.md +61 -61
- package/docs-site/docs/FAQ.md +50 -50
- package/docs-site/docs/Plugins.md +61 -61
- package/docs-site/docs/Usage.md +72 -72
- package/jest.config.js +20 -13
- package/package.json +20 -3
- package/plugin.config.json +14 -0
- package/public/src/App.jsx +57 -57
- package/release.config.js +36 -23
- package/scripts/banner-injector.js +89 -0
- package/scripts/ci-runner.js +51 -0
- package/scripts/repair-fixtures.js +30 -0
- package/scripts/setup.js +31 -0
- package/scripts/test-global-setup.js +18 -0
- package/scripts/verify-fixture-mocks.js +45 -0
- package/scripts/verify-fixtures.js +36 -0
- package/server.js +31 -31
- package/src/config/load-config.js +33 -35
- package/src/config/load-plugin-config.js +56 -0
- package/src/config/validate-plugin-schema.js +28 -0
- package/src/config/validate-schema.js +107 -49
- package/src/core/create-pipeline.js +96 -82
- package/src/core/plugin-contracts.js +21 -0
- package/src/core/plugin-registry.js +48 -61
- package/src/dag/dag-engine.js +69 -69
- package/src/evaluate/evaluator.js +44 -44
- package/src/evaluate/scoring.js +73 -73
- package/src/loader/csv-loader.js +30 -30
- package/src/loader/directory-loader.js +37 -37
- package/src/loader/html-loader.js +57 -57
- package/src/loader/markdown-loader.js +58 -58
- package/src/mocks/openai-embedder.js +30 -0
- package/src/mocks/openai-llm.js +18 -0
- package/src/mocks/pdf-loader.js +17 -0
- package/src/mocks/pinecone-retriever.js +25 -0
- package/src/reranker/llm-reranker.js +34 -49
- package/src/utils/ci/diagnostic-reporter.js +36 -0
- package/src/utils/logger.js +29 -29
- package/src/utils/retry.js +42 -42
- package/src/utils/validate-plugin-contract.js +36 -0
- package/.github/workflows/release.yml +0 -21
package/README.md
CHANGED
|
@@ -1,116 +1,117 @@
|
|
|
1
|
-
# @DevilsDev/rag-pipeline-utils
|
|
2
|
-
|
|
3
|
-
[](https://github.com/DevilsDev/rag-pipeline-utils/actions)
|
|
4
|
-
[](https://codecov.io/gh/DevilsDev/rag-pipeline-utils)
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
- ✅
|
|
14
|
-
- ✅
|
|
15
|
-
- ✅
|
|
16
|
-
- ✅
|
|
17
|
-
- ✅
|
|
18
|
-
- ✅
|
|
19
|
-
- ✅
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
rag-pipeline
|
|
63
|
-
rag-pipeline
|
|
64
|
-
rag-pipeline
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
├──
|
|
87
|
-
├──
|
|
88
|
-
├──
|
|
89
|
-
├──
|
|
90
|
-
/
|
|
91
|
-
/
|
|
92
|
-
/
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
1
|
+
# @DevilsDev/rag-pipeline-utils
|
|
2
|
+
|
|
3
|
+
[](https://github.com/DevilsDev/rag-pipeline-utils/actions)
|
|
4
|
+
[](https://codecov.io/gh/DevilsDev/rag-pipeline-utils)
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
**A modular Node.js toolkit for building RAG (Retrieval-Augmented Generation) pipelines with clean abstractions, pluggable components, and scalable architecture.**
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- ✅ Plugin-based architecture for RAG pipelines
|
|
14
|
+
- ✅ Embedding + retrieval abstraction
|
|
15
|
+
- ✅ Vector DB integrations (e.g., Pinecone)
|
|
16
|
+
- ✅ Modular document loaders (PDF, HTML, Markdown, CSV, Directory)
|
|
17
|
+
- ✅ CLI with `.ragrc.json` config fallback
|
|
18
|
+
- ✅ Retry, backoff, and logging built-in
|
|
19
|
+
- ✅ Reranker support and evaluation tooling
|
|
20
|
+
- ✅ React dashboard for evaluation results
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install @yourorg/rag-pipeline-utils
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
import { createRagPipeline } from '@yourorg/rag-pipeline-utils';
|
|
36
|
+
|
|
37
|
+
const rag = createRagPipeline({
|
|
38
|
+
loader: 'markdown',
|
|
39
|
+
embedder: 'openai',
|
|
40
|
+
retriever: 'pinecone',
|
|
41
|
+
llm: 'openai-gpt-4',
|
|
42
|
+
useReranker: true
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const answer = await rag.query('What is a vector database?');
|
|
46
|
+
console.log(answer);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Testing
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm test
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## CLI
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
rag-pipeline ingest ./docs/my.pdf --loader pdf
|
|
63
|
+
rag-pipeline query "Explain RAG pipelines" --llm openai-gpt-4
|
|
64
|
+
rag-pipeline evaluate ./fixtures/sample-eval-dataset.json
|
|
65
|
+
rag-pipeline rerank "Explain embeddings" --retriever pinecone
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Supports `.ragrc.json` fallback configuration:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"loader": "directory",
|
|
73
|
+
"embedder": "openai",
|
|
74
|
+
"retriever": "pinecone",
|
|
75
|
+
"llm": "openai-gpt-4",
|
|
76
|
+
"useReranker": true
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Project Structure
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
/src
|
|
86
|
+
├── core/ # Pipeline + registry
|
|
87
|
+
├── loader/ # Loaders for md, html, csv, dir
|
|
88
|
+
├── reranker/ # LLM-based context reranker
|
|
89
|
+
├── evaluate/ # Scoring, batch QA evaluation
|
|
90
|
+
├── utils/ # Logger, retry, schema
|
|
91
|
+
/bin/cli.js # CLI entrypoint
|
|
92
|
+
/__tests__/ # Unit, integration, snapshot tests
|
|
93
|
+
/public/ # Evaluation dashboard (React)
|
|
94
|
+
.github/workflows/ci.yml # CI config
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Evaluation Dashboard
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
node server.js
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Visit: [http://localhost:3000](http://localhost:3000) → Visualizes metrics, BLEU/ROUGE, pass rate.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## License
|
|
110
|
+
|
|
111
|
+
Apache-2.0
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 👤 Author
|
|
116
|
+
|
|
117
|
+
Ali Kahwaji — [@DevilsDev](https://github.com/DevilsDev)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"loader": { "pdf": "./src/mocks/pdf-loader.js" },
|
|
3
|
+
"embedder": { "openai": "./src/mocks/openai-embedder.js" },
|
|
4
|
+
"retriever": { "pinecone": "./src/mocks/pinecone-retriever.js" },
|
|
5
|
+
"llm": { "openai": "./src/mocks/openai-llm.js" },
|
|
6
|
+
"namespace": "cli-config-test",
|
|
7
|
+
"pipeline": ["loader", "embedder", "retriever"]
|
|
8
|
+
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
[
|
|
2
|
-
{
|
|
3
|
-
"prompt": "What is a vector database?",
|
|
4
|
-
"expected": "A vector database is a system optimized for storing and retrieving data represented as vectors, often used in similarity search."
|
|
5
|
-
},
|
|
6
|
-
{
|
|
7
|
-
"prompt": "Explain what chunking means in RAG.",
|
|
8
|
-
"expected": "Chunking is the process of splitting documents into smaller, manageable pieces for embedding and retrieval in a RAG pipeline."
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
"prompt": "What is the role of embedding in a RAG pipeline?",
|
|
12
|
-
"expected": "Embeddings convert text into numerical vector form so they can be compared in a vector database during retrieval."
|
|
13
|
-
}
|
|
14
|
-
]
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"prompt": "What is a vector database?",
|
|
4
|
+
"expected": "A vector database is a system optimized for storing and retrieving data represented as vectors, often used in similarity search."
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
"prompt": "Explain what chunking means in RAG.",
|
|
8
|
+
"expected": "Chunking is the process of splitting documents into smaller, manageable pieces for embedding and retrieval in a RAG pipeline."
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"prompt": "What is the role of embedding in a RAG pipeline?",
|
|
12
|
+
"expected": "Embeddings convert text into numerical vector form so they can be compared in a vector database during retrieval."
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
15
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
%PDF-1.4\n%âãÏÓ\n1 0 obj\n<<>>\nendobj\nxref\n0 2\n0000000000 65535 f\n0000000010 00000 n\ntrailer\n<<>>\nstartxref\n9\n%%EOF
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock OpenAI Embedder Plugin
|
|
3
|
+
* Implements: embedder.embed(docs), embedder.embedQuery(query)
|
|
4
|
+
*/
|
|
5
|
+
export default class OpenAIEmbedder {
|
|
6
|
+
embed(documents) {
|
|
7
|
+
return documents.map(doc => ({
|
|
8
|
+
id: doc.id,
|
|
9
|
+
values: [0.1, 0.2, 0.3],
|
|
10
|
+
}));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
embedQuery(query) {
|
|
14
|
+
return [0.1, 0.2, 0.3];
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock PDF Loader Plugin
|
|
3
|
+
* Implements: loader.load(filePath)
|
|
4
|
+
*/
|
|
5
|
+
export default class PdfLoader {
|
|
6
|
+
/**
|
|
7
|
+
* Loads a file and returns mock document chunks.
|
|
8
|
+
* @param {string} filePath
|
|
9
|
+
* @returns {Array<{ id: string, content: string }>}
|
|
10
|
+
*/
|
|
11
|
+
load(filePath) {
|
|
12
|
+
return [
|
|
13
|
+
{ id: 'doc1', content: `Loaded content from ${filePath}` },
|
|
14
|
+
{ id: 'doc2', content: 'Second document content' },
|
|
15
|
+
];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock Pinecone Retriever Plugin
|
|
3
|
+
* Implements: retriever.store(vectors), retriever.search(queryVector)
|
|
4
|
+
*/
|
|
5
|
+
export default class PineconeRetriever {
|
|
6
|
+
constructor() {
|
|
7
|
+
this._store = [];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Stores embedded vectors.
|
|
12
|
+
* @param {Array<{ id: string, values: number[] }>} vectors
|
|
13
|
+
*/
|
|
14
|
+
store(vectors) {
|
|
15
|
+
this._store = vectors;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Searches mock memory and returns matching docs.
|
|
20
|
+
* @param {number[]} queryVector
|
|
21
|
+
* @returns {Array<{ id: string, score: number }>}
|
|
22
|
+
*/
|
|
23
|
+
search(queryVector) {
|
|
24
|
+
return this._store.map(v => ({ id: v.id, score: 0.99 }));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"loader": {
|
|
3
|
+
"pdf": "./src/mocks/pdf-loader.js"
|
|
4
|
+
},
|
|
5
|
+
"embedder": {
|
|
6
|
+
"openai": "./src/mocks/openai-embedder.js"
|
|
7
|
+
},
|
|
8
|
+
"retriever": {
|
|
9
|
+
"pinecone": "./src/mocks/pinecone-retriever.js"
|
|
10
|
+
},
|
|
11
|
+
"llm": {
|
|
12
|
+
"openai": "./src/mocks/openai-llm.js"
|
|
13
|
+
},
|
|
14
|
+
"namespace": "cli-config-test",
|
|
15
|
+
"pipeline": ["loader", "embedder", "retriever"]
|
|
16
|
+
}
|
|
@@ -1,44 +1,98 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Version:
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Version: 1.1.0
|
|
3
|
+
* Description: Final CLI config fallback integration test with fixture mock copying and validation
|
|
4
|
+
* Author: Ali Kahwaji
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { execSync } from 'child_process';
|
|
8
|
+
import {
|
|
9
|
+
mkdirSync,
|
|
10
|
+
rmSync,
|
|
11
|
+
writeFileSync,
|
|
12
|
+
copyFileSync,
|
|
13
|
+
existsSync,
|
|
14
|
+
readdirSync,
|
|
15
|
+
readFileSync
|
|
16
|
+
} from 'fs';
|
|
17
|
+
import { join, resolve } from 'path';
|
|
18
|
+
import { fileURLToPath } from 'url';
|
|
19
|
+
|
|
20
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
21
|
+
const __dirname = resolve(__filename, '..');
|
|
22
|
+
|
|
23
|
+
const CLI_PATH = resolve('bin/cli.js');
|
|
24
|
+
const TEMP_TEST_DIR = resolve('__tests__/__temp__/cli-config-fallback');
|
|
25
|
+
const FIXTURE_CONFIG = join(TEMP_TEST_DIR, '.ragrc.json');
|
|
26
|
+
const FIXTURE_PDF = resolve('__tests__/fixtures/sample.pdf');
|
|
27
|
+
|
|
28
|
+
// Fixture sources
|
|
29
|
+
const FIXTURE_SRC = resolve('__tests__/fixtures/src/mocks');
|
|
30
|
+
const PDF_LOADER_SRC = join(FIXTURE_SRC, 'pdf-loader.js');
|
|
31
|
+
const EMBEDDER_SRC = join(FIXTURE_SRC, 'openai-embedder.js');
|
|
32
|
+
const RETRIEVER_SRC = join(FIXTURE_SRC, 'pinecone-retriever.js');
|
|
33
|
+
const LLM_SRC = join(FIXTURE_SRC, 'openai-llm.js');
|
|
34
|
+
|
|
35
|
+
const FIXTURE_CONFIG_OBJECT = {
|
|
36
|
+
loader: { pdf: './src/mocks/pdf-loader.js' },
|
|
37
|
+
embedder: { openai: './src/mocks/openai-embedder.js' },
|
|
38
|
+
retriever: { pinecone: './src/mocks/pinecone-retriever.js' },
|
|
39
|
+
llm: { openai: './src/mocks/openai-llm.js' },
|
|
40
|
+
namespace: 'cli-config-test',
|
|
41
|
+
pipeline: ['loader', 'embedder', 'retriever']
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
describe('CLI integration with .ragrc.json config fallback', () => {
|
|
45
|
+
beforeAll(() => {
|
|
46
|
+
rmSync(TEMP_TEST_DIR, { recursive: true, force: true });
|
|
47
|
+
mkdirSync(join(TEMP_TEST_DIR, 'src/mocks'), { recursive: true });
|
|
48
|
+
|
|
49
|
+
// Assert existence
|
|
50
|
+
[FIXTURE_PDF, PDF_LOADER_SRC, EMBEDDER_SRC, RETRIEVER_SRC, LLM_SRC].forEach(file => {
|
|
51
|
+
if (!existsSync(file)) throw new Error(`[FATAL] Missing required fixture: ${file}`);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Copy fixture PDF
|
|
55
|
+
copyFileSync(FIXTURE_PDF, join(TEMP_TEST_DIR, 'sample.pdf'));
|
|
56
|
+
|
|
57
|
+
// Copy mock plugins into temp dir
|
|
58
|
+
copyFileSync(PDF_LOADER_SRC, join(TEMP_TEST_DIR, 'src/mocks/pdf-loader.js'));
|
|
59
|
+
copyFileSync(EMBEDDER_SRC, join(TEMP_TEST_DIR, 'src/mocks/openai-embedder.js'));
|
|
60
|
+
copyFileSync(RETRIEVER_SRC, join(TEMP_TEST_DIR, 'src/mocks/pinecone-retriever.js'));
|
|
61
|
+
copyFileSync(LLM_SRC, join(TEMP_TEST_DIR, 'src/mocks/openai-llm.js'));
|
|
62
|
+
|
|
63
|
+
// Write valid .ragrc.json
|
|
64
|
+
writeFileSync(FIXTURE_CONFIG, JSON.stringify(FIXTURE_CONFIG_OBJECT, null, 2));
|
|
65
|
+
|
|
66
|
+
console.debug('[DEBUG] .ragrc.json contents:\n', JSON.stringify(FIXTURE_CONFIG_OBJECT, null, 2));
|
|
67
|
+
console.debug('[SETUP] Temp dir:', TEMP_TEST_DIR);
|
|
68
|
+
console.debug('[SETUP] Contents:', readdirSync(TEMP_TEST_DIR));
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
afterAll(() => {
|
|
72
|
+
rmSync(TEMP_TEST_DIR, { recursive: true, force: true });
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('validates plugin sections contain resolvable names', () => {
|
|
76
|
+
const config = JSON.parse(readFileSync(FIXTURE_CONFIG, 'utf-8'));
|
|
77
|
+
['loader', 'embedder', 'retriever', 'llm'].forEach(type => {
|
|
78
|
+
expect(typeof config[type]).toBe('object');
|
|
79
|
+
expect(Object.keys(config[type]).length).toBeGreaterThan(0);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('executes CLI ingest using config fallback', () => {
|
|
84
|
+
const result = execSync(`node ${CLI_PATH} ingest sample.pdf`, {
|
|
85
|
+
cwd: TEMP_TEST_DIR,
|
|
86
|
+
encoding: 'utf-8'
|
|
87
|
+
});
|
|
88
|
+
expect(result).toMatch(/Ingestion complete/);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('executes CLI query using config fallback', () => {
|
|
92
|
+
const result = execSync(`node ${CLI_PATH} query "What is this test about?"`, {
|
|
93
|
+
cwd: TEMP_TEST_DIR,
|
|
94
|
+
encoding: 'utf-8'
|
|
95
|
+
});
|
|
96
|
+
expect(result).toMatch(/Answer:/);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -1,52 +1,67 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Version:
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import fs from 'fs';
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Version: 1.1.1
|
|
3
|
+
* Description: Integration tests for loading and validating .ragrc.json via loadRagConfig()
|
|
4
|
+
* Author: Ali Kahwaji
|
|
5
|
+
* File: __tests__/integration/config/load-config.test.js
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import { copyFileSync, mkdirSync, rmSync, existsSync } from 'fs';
|
|
10
|
+
import { join, resolve } from 'path';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
import { loadRagConfig } from '../../../src/config/load-config.js';
|
|
13
|
+
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
+
const __dirname = resolve(__filename, '..');
|
|
16
|
+
|
|
17
|
+
// Fixture paths
|
|
18
|
+
const FIXTURE_DIR = resolve(__dirname, '../../fixtures');
|
|
19
|
+
const VALID_FIXTURE = join(FIXTURE_DIR, 'valid-ragrc.json');
|
|
20
|
+
const INVALID_FIXTURE = join(FIXTURE_DIR, 'invalid-ragrc.json');
|
|
21
|
+
|
|
22
|
+
// Temp directory used during tests
|
|
23
|
+
const TEMP_DIR = resolve('__tests__', '__temp__', 'load-config');
|
|
24
|
+
const TEMP_CONFIG = join(TEMP_DIR, '.ragrc.json');
|
|
25
|
+
|
|
26
|
+
// Ensure fixtures are available before copying
|
|
27
|
+
function assertFixturesExist() {
|
|
28
|
+
const required = [VALID_FIXTURE, INVALID_FIXTURE];
|
|
29
|
+
required.forEach(file => {
|
|
30
|
+
if (!existsSync(file)) {
|
|
31
|
+
throw new Error(`❌ Required test fixture missing: ${file}`);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
describe('loadRagConfig()', () => {
|
|
37
|
+
beforeAll(() => {
|
|
38
|
+
rmSync(TEMP_DIR, { recursive: true, force: true });
|
|
39
|
+
mkdirSync(TEMP_DIR, { recursive: true });
|
|
40
|
+
|
|
41
|
+
assertFixturesExist();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
afterAll(() => {
|
|
45
|
+
rmSync(TEMP_DIR, { recursive: true, force: true });
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test('loads a valid .ragrc.json config file successfully', () => {
|
|
49
|
+
copyFileSync(VALID_FIXTURE, TEMP_CONFIG);
|
|
50
|
+
|
|
51
|
+
const config = loadRagConfig(TEMP_CONFIG);
|
|
52
|
+
expect(config).toBeDefined();
|
|
53
|
+
expect(config.namespace).toBe('cli-config-test');
|
|
54
|
+
expect(config.loader?.pdf).toBe('./src/mocks/pdf-loader.js');
|
|
55
|
+
expect(config.pipeline).toEqual(expect.arrayContaining(['loader', 'embedder', 'retriever']));
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('throws validation error for invalid .ragrc.json config', () => {
|
|
59
|
+
copyFileSync(INVALID_FIXTURE, TEMP_CONFIG);
|
|
60
|
+
expect(() => loadRagConfig(TEMP_CONFIG)).toThrow(/Config validation failed/);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('throws error if config file does not exist', () => {
|
|
64
|
+
const NON_EXISTENT = join(TEMP_DIR, 'missing.json');
|
|
65
|
+
expect(() => loadRagConfig(NON_EXISTENT)).toThrow(/Config file not found/);
|
|
66
|
+
});
|
|
67
|
+
});
|