@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.
Files changed (72) hide show
  1. package/.codecov.yml +21 -0
  2. package/.dockerignore +14 -14
  3. package/.eslintignore +5 -0
  4. package/.eslintrc.json +21 -0
  5. package/.github/workflows/ci.yml +64 -42
  6. package/.husky/pre-commit +5 -0
  7. package/CHANGELOG.md +46 -0
  8. package/Dockerfile +22 -22
  9. package/LICENSE +674 -674
  10. package/README.md +117 -116
  11. package/__tests__/fixtures/.ragrc.json +8 -0
  12. package/__tests__/fixtures/invalid-ragrc.json +4 -0
  13. package/__tests__/fixtures/sample-eval-dataset.json +14 -14
  14. package/__tests__/fixtures/sample.pdf +1 -0
  15. package/__tests__/fixtures/src/mocks/openai-embedder.js +16 -0
  16. package/__tests__/fixtures/src/mocks/openai-llm.js +9 -0
  17. package/__tests__/fixtures/src/mocks/pdf-loader.js +17 -0
  18. package/__tests__/fixtures/src/mocks/pinecone-retriever.js +26 -0
  19. package/__tests__/fixtures/valid-ragrc.json +16 -0
  20. package/__tests__/integration/cli/config-flow.test.js +98 -44
  21. package/__tests__/integration/config/load-config.test.js +67 -52
  22. package/__tests__/unit/config/validate-schema.test.js +121 -0
  23. package/__tests__/unit/core/plugin-registry.test.js +55 -55
  24. package/__tests__/unit/reranker/llm-reranker.test.js +18 -42
  25. package/__tests__/unit/reranker/reranker.enriched.test.js +19 -0
  26. package/__tests__/unit/reranker/reranker.fallback.test.js +15 -0
  27. package/__tests__/unit/reranker/reranker.snapshot.test.js +15 -17
  28. package/__tests__/unit/reranker/reranker.structured-output.test.js +17 -0
  29. package/bin/cli.js +62 -168
  30. package/docs-site/docs/Architecture.md +76 -76
  31. package/docs-site/docs/CLI.md +69 -69
  32. package/docs-site/docs/Evaluation.md +61 -61
  33. package/docs-site/docs/FAQ.md +50 -50
  34. package/docs-site/docs/Plugins.md +61 -61
  35. package/docs-site/docs/Usage.md +72 -72
  36. package/jest.config.js +20 -13
  37. package/package.json +20 -3
  38. package/plugin.config.json +14 -0
  39. package/public/src/App.jsx +57 -57
  40. package/release.config.js +36 -23
  41. package/scripts/banner-injector.js +89 -0
  42. package/scripts/ci-runner.js +51 -0
  43. package/scripts/repair-fixtures.js +30 -0
  44. package/scripts/setup.js +31 -0
  45. package/scripts/test-global-setup.js +18 -0
  46. package/scripts/verify-fixture-mocks.js +45 -0
  47. package/scripts/verify-fixtures.js +36 -0
  48. package/server.js +31 -31
  49. package/src/config/load-config.js +33 -35
  50. package/src/config/load-plugin-config.js +56 -0
  51. package/src/config/validate-plugin-schema.js +28 -0
  52. package/src/config/validate-schema.js +107 -49
  53. package/src/core/create-pipeline.js +96 -82
  54. package/src/core/plugin-contracts.js +21 -0
  55. package/src/core/plugin-registry.js +48 -61
  56. package/src/dag/dag-engine.js +69 -69
  57. package/src/evaluate/evaluator.js +44 -44
  58. package/src/evaluate/scoring.js +73 -73
  59. package/src/loader/csv-loader.js +30 -30
  60. package/src/loader/directory-loader.js +37 -37
  61. package/src/loader/html-loader.js +57 -57
  62. package/src/loader/markdown-loader.js +58 -58
  63. package/src/mocks/openai-embedder.js +30 -0
  64. package/src/mocks/openai-llm.js +18 -0
  65. package/src/mocks/pdf-loader.js +17 -0
  66. package/src/mocks/pinecone-retriever.js +25 -0
  67. package/src/reranker/llm-reranker.js +34 -49
  68. package/src/utils/ci/diagnostic-reporter.js +36 -0
  69. package/src/utils/logger.js +29 -29
  70. package/src/utils/retry.js +42 -42
  71. package/src/utils/validate-plugin-contract.js +36 -0
  72. package/.github/workflows/release.yml +0 -21
package/README.md CHANGED
@@ -1,116 +1,117 @@
1
- # @DevilsDev/rag-pipeline-utils
2
-
3
- [![CI](https://github.com/DevilsDev/rag-pipeline-utils/actions/workflows/ci.yml/badge.svg)](https://github.com/DevilsDev/rag-pipeline-utils/actions)
4
- [![codecov](https://codecov.io/gh/DevilsDev/rag-pipeline-utils/branch/main/graph/badge.svg)](https://codecov.io/gh/DevilsDev/rag-pipeline-utils)
5
-
6
- **A modular Node.js toolkit for building RAG (Retrieval-Augmented Generation) pipelines with clean abstractions, pluggable components, and scalable architecture.**
7
-
8
- ---
9
-
10
- ## Features
11
-
12
- - ✅ Plugin-based architecture for RAG pipelines
13
- - ✅ Embedding + retrieval abstraction
14
- - ✅ Vector DB integrations (e.g., Pinecone)
15
- - ✅ Modular document loaders (PDF, HTML, Markdown, CSV, Directory)
16
- - ✅ CLI with `.ragrc.json` config fallback
17
- - ✅ Retry, backoff, and logging built-in
18
- - ✅ Reranker support and evaluation tooling
19
- - ✅ React dashboard for evaluation results
20
-
21
- ---
22
-
23
- ## Installation
24
-
25
- ```bash
26
- npm install @yourorg/rag-pipeline-utils
27
- ```
28
-
29
- ---
30
-
31
- ## Usage
32
-
33
- ```js
34
- import { createRagPipeline } from '@yourorg/rag-pipeline-utils';
35
-
36
- const rag = createRagPipeline({
37
- loader: 'markdown',
38
- embedder: 'openai',
39
- retriever: 'pinecone',
40
- llm: 'openai-gpt-4',
41
- useReranker: true
42
- });
43
-
44
- const answer = await rag.query('What is a vector database?');
45
- console.log(answer);
46
- ```
47
-
48
- ---
49
-
50
- ## Testing
51
-
52
- ```bash
53
- npm test
54
- ```
55
-
56
- ---
57
-
58
- ## CLI
59
-
60
- ```bash
61
- rag-pipeline ingest ./docs/my.pdf --loader pdf
62
- rag-pipeline query "Explain RAG pipelines" --llm openai-gpt-4
63
- rag-pipeline evaluate ./fixtures/sample-eval-dataset.json
64
- rag-pipeline rerank "Explain embeddings" --retriever pinecone
65
- ```
66
-
67
- Supports `.ragrc.json` fallback configuration:
68
-
69
- ```json
70
- {
71
- "loader": "directory",
72
- "embedder": "openai",
73
- "retriever": "pinecone",
74
- "llm": "openai-gpt-4",
75
- "useReranker": true
76
- }
77
- ```
78
-
79
- ---
80
-
81
- ## Project Structure
82
-
83
- ```
84
- /src
85
- ├── core/ # Pipeline + registry
86
- ├── loader/ # Loaders for md, html, csv, dir
87
- ├── reranker/ # LLM-based context reranker
88
- ├── evaluate/ # Scoring, batch QA evaluation
89
- ├── utils/ # Logger, retry, schema
90
- /bin/cli.js # CLI entrypoint
91
- /__tests__/ # Unit, integration, snapshot tests
92
- /public/ # Evaluation dashboard (React)
93
- .github/workflows/ci.yml # CI config
94
- ```
95
-
96
- ---
97
-
98
- ## Evaluation Dashboard
99
-
100
- ```bash
101
- node server.js
102
- ```
103
-
104
- Visit: [http://localhost:3000](http://localhost:3000) → Visualizes metrics, BLEU/ROUGE, pass rate.
105
-
106
- ---
107
-
108
- ## License
109
-
110
- Apache-2.0
111
-
112
- ---
113
-
114
- ## 👤 Author
115
-
116
- Ali Kahwaji — [@DevilsDev](https://github.com/DevilsDev)
1
+ # @DevilsDev/rag-pipeline-utils
2
+
3
+ [![CI](https://github.com/DevilsDev/rag-pipeline-utils/actions/workflows/ci.yml/badge.svg)](https://github.com/DevilsDev/rag-pipeline-utils/actions)
4
+ [![codecov](https://codecov.io/gh/DevilsDev/rag-pipeline-utils/branch/main/graph/badge.svg)](https://codecov.io/gh/DevilsDev/rag-pipeline-utils)
5
+ ![Release](https://img.shields.io/github/v/release/DevilsDev/rag-pipeline-utils?label=release)
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
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "loader": "./src/mocks/pdf-loader.js",
3
+ "namespace": 12345
4
+ }
@@ -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,9 @@
1
+ /**
2
+ * Mock OpenAI LLM Plugin
3
+ * Implements: llm.ask(prompt)
4
+ */
5
+ export default class OpenAILLM {
6
+ ask(prompt) {
7
+ return `Answer: Mocked response to "${prompt}"`;
8
+ }
9
+ }
@@ -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: 0.1.0
3
- * Path: /__tests__/integration/cli/config-flow.test.js
4
- * Description: Integration tests for CLI fallback to .ragrc.json and full flow execution
5
- * Author: Ali Kahwaji
6
- */
7
-
8
- import fs from 'fs';
9
- import path from 'path';
10
- import { execSync } from 'child_process';
11
-
12
- const CONFIG_PATH = path.resolve(process.cwd(), '.ragrc.json');
13
- const CLI_PATH = path.resolve('./bin/cli.js');
14
-
15
- const validConfig = {
16
- loader: 'pdf',
17
- embedder: 'openai',
18
- retriever: 'pinecone',
19
- llm: 'openai-gpt-4',
20
- chunk: {
21
- strategy: 'semantic',
22
- size: 256
23
- }
24
- };
25
-
26
- describe('CLI integration with .ragrc.json config fallback', () => {
27
- beforeEach(() => {
28
- fs.writeFileSync(CONFIG_PATH, JSON.stringify(validConfig, null, 2));
29
- });
30
-
31
- afterEach(() => {
32
- if (fs.existsSync(CONFIG_PATH)) fs.unlinkSync(CONFIG_PATH);
33
- });
34
-
35
- test('executes CLI ingest using config fallback', () => {
36
- const result = execSync(`node ${CLI_PATH} ingest ./sample.pdf`, { encoding: 'utf-8' });
37
- expect(result).toContain('Ingestion complete');
38
- });
39
-
40
- test('executes CLI query using config fallback', () => {
41
- const output = execSync(`node ${CLI_PATH} query "What is a vector?"`, { encoding: 'utf-8' });
42
- expect(output).toContain('Answer:');
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: 0.1.0
3
- * Path: /__tests__/integration/config/load-config.test.js
4
- * Description: Integration tests for loading and validating .ragrc.json config
5
- * Author: Ali Kahwaji
6
- */
7
-
8
- import fs from 'fs';
9
- import path from 'path';
10
- import { loadRagConfig } from '../../../src/config/load-config.js';
11
-
12
- const FIXTURE_PATH = path.resolve(process.cwd(), '.ragrc.json');
13
-
14
- const validConfig = {
15
- loader: 'pdf',
16
- embedder: 'openai',
17
- retriever: 'pinecone',
18
- llm: 'openai-gpt-4',
19
- chunk: {
20
- strategy: 'semantic',
21
- size: 500
22
- }
23
- };
24
-
25
- const invalidConfig = {
26
- loader: 'pdf',
27
- chunk: { size: 'large' } // Missing required keys + invalid type
28
- };
29
-
30
- describe('loadRagConfig()', () => {
31
- afterEach(() => {
32
- if (fs.existsSync(FIXTURE_PATH)) {
33
- fs.unlinkSync(FIXTURE_PATH);
34
- }
35
- });
36
-
37
- test('loads a valid .ragrc.json config file successfully', () => {
38
- fs.writeFileSync(FIXTURE_PATH, JSON.stringify(validConfig, null, 2));
39
- const result = loadRagConfig();
40
- expect(result).toMatchObject(validConfig);
41
- });
42
-
43
- test('throws validation error for invalid .ragrc.json config', () => {
44
- fs.writeFileSync(FIXTURE_PATH, JSON.stringify(invalidConfig, null, 2));
45
- expect(() => loadRagConfig()).toThrow(/Invalid config/);
46
- });
47
-
48
- test('throws error if config file does not exist', () => {
49
- expect(() => loadRagConfig()).toThrow(/Config file not found/);
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
+ });