@devilsdev/rag-pipeline-utils 2.3.1 → 2.4.1
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 +94 -480
- package/contracts/loader-contract.json +11 -6
- package/contracts/reranker-contract.json +18 -26
- package/dist/index.cjs +21190 -47
- package/dist/index.d.ts +298 -68
- package/dist/index.mjs +9 -76
- package/package.json +37 -11
- package/src/agentic/agentic-pipeline.js +235 -0
- package/src/agentic/iterative-retriever.js +213 -0
- package/src/agentic/query-planner.js +208 -0
- package/src/agentic/self-critique.js +102 -0
- package/src/ai/adaptive-retrieval.js +0 -3
- package/src/ai/federated-learning.js +0 -3
- package/src/ai/federation.js +1 -6
- package/src/ai/index.js +9 -20
- package/src/ai/model-training.js +0 -3
- package/src/ai/multimodal-processing.js +0 -3
- package/src/ai/multimodal.js +1 -6
- package/src/ai/orchestrator.js +1 -6
- package/src/ai/retrieval-engine.js +1 -6
- package/src/chunking/chunking-engine.js +142 -0
- package/src/chunking/strategies/fixed-size.js +54 -0
- package/src/chunking/strategies/recursive.js +127 -0
- package/src/chunking/strategies/semantic.js +128 -0
- package/src/chunking/strategies/sentence.js +32 -0
- package/src/chunking/strategies/structure-aware.js +138 -0
- package/src/citation/citation-tracker.js +161 -0
- package/src/citation/hallucination-detector.js +74 -0
- package/src/citation/source-mapper.js +95 -0
- package/src/cli/commands/ai-ml/adaptive-commands.js +178 -0
- package/src/cli/commands/ai-ml/federated-commands.js +207 -0
- package/src/cli/commands/ai-ml/index.js +17 -0
- package/src/cli/commands/ai-ml/multimodal-commands.js +187 -0
- package/src/cli/commands/ai-ml/shared.js +51 -0
- package/src/cli/commands/ai-ml/training-commands.js +228 -0
- package/src/cli/commands/ai-ml.js +176 -757
- package/src/cli/commands/plugin-hub/certification-commands.js +221 -0
- package/src/cli/commands/plugin-hub/event-handlers.js +64 -0
- package/src/cli/commands/plugin-hub/hub-commands.js +290 -0
- package/src/cli/commands/plugin-hub/review-commands.js +78 -0
- package/src/cli/commands/plugin-hub.js +106 -782
- package/src/cli/diagnostics/config-checker.js +81 -0
- package/src/cli/diagnostics/dependency-checker.js +69 -0
- package/src/cli/diagnostics/environment-checker.js +45 -0
- package/src/cli/diagnostics/performance-checker.js +51 -0
- package/src/cli/diagnostics/plugin-checker.js +106 -0
- package/src/cli/diagnostics/security-checker.js +61 -0
- package/src/cli/doctor-command.js +70 -369
- package/src/cli/enhanced-cli-commands.js +162 -706
- package/src/cli/handlers/config-handler.js +126 -0
- package/src/cli/handlers/diagnostics-handler.js +113 -0
- package/src/cli/handlers/ingest-handler.js +42 -0
- package/src/cli/handlers/init-handler.js +51 -0
- package/src/cli/handlers/query-handler.js +45 -0
- package/src/cli/handlers/run-handler.js +181 -0
- package/src/cli/interactive-wizard.js +99 -723
- package/src/cli/shared/cli-utils.js +89 -0
- package/src/cli/wizard/configuration.js +148 -0
- package/src/cli/wizard/observability.js +79 -0
- package/src/cli/wizard/performance.js +76 -0
- package/src/cli/wizard/plugin-selection.js +297 -0
- package/src/cli/wizard/preview-save.js +172 -0
- package/src/cli/wizard/project-setup.js +66 -0
- package/src/config/memory-optimization.js +3 -3
- package/src/connectors/anthropic-connector.js +179 -0
- package/src/connectors/base-connector.js +94 -0
- package/src/connectors/cohere-connector.js +143 -0
- package/src/connectors/local-embedder.js +171 -0
- package/src/connectors/memory-retriever.js +150 -0
- package/src/connectors/ollama-connector.js +205 -0
- package/src/connectors/openai-connector.js +173 -0
- package/src/core/create-pipeline.js +21 -1
- package/src/core/observability/tracing.js +2 -1
- package/src/core/pipeline-factory.js +0 -1
- package/src/core/plugin-registry.js +14 -14
- package/src/cost/cost-calculator.js +146 -0
- package/src/cost/cost-tracker.js +260 -0
- package/src/cost/token-budget.js +245 -0
- package/src/dag/core/execution-scheduler.js +2 -1
- package/src/dag/core/topology-validation.js +0 -3
- package/src/dag/dag-engine.js +3 -5
- package/src/dag/dag-node.js +0 -1
- package/src/dag/enhanced-dag-engine.js +171 -99
- package/src/dashboard/dashboard-generator.js +642 -0
- package/src/dashboard/metrics-aggregator.js +409 -0
- package/src/debug/execution-tracer.js +210 -0
- package/src/debug/trace-inspector.js +281 -0
- package/src/dev/dev-server.js +5 -5
- package/src/dev/hot-reload.js +3 -2
- package/src/dx/integration-templates.js +0 -3
- package/src/ecosystem/plugin-analytics-dashboard.js +2 -2
- package/src/ecosystem/plugin-hub.js +2 -2
- package/src/enterprise/audit-logging.js +2 -2
- package/src/enterprise/sso-integration.js +52 -32
- package/src/evaluate/context-metrics.js +127 -0
- package/src/evaluate/evaluator.js +4 -2
- package/src/evaluate/faithfulness.js +117 -0
- package/src/evaluate/groundedness.js +60 -0
- package/src/evaluate/pipeline-evaluator.js +156 -0
- package/src/evaluate/relevance.js +129 -0
- package/src/evaluate/scoring.js +27 -0
- package/src/graph/entity-extractor.js +183 -0
- package/src/graph/graph-index.js +113 -0
- package/src/graph/graph-retriever.js +244 -0
- package/src/graph/knowledge-graph.js +256 -0
- package/src/guardrails/guardrails-pipeline.js +136 -0
- package/src/guardrails/post-generation-guard.js +170 -0
- package/src/guardrails/pre-retrieval-guard.js +161 -0
- package/src/guardrails/retrieval-guard.js +126 -0
- package/src/index.js +255 -9
- package/src/loader/html-loader.js +4 -15
- package/src/loader/markdown-loader.js +4 -15
- package/src/mcp/mcp-server.js +199 -0
- package/src/mcp/mcp-tool-builder.js +121 -0
- package/src/observability/audit-logger.js +0 -2
- package/src/observability/event-logger.js +2 -1
- package/src/observability/security-monitor.js +0 -2
- package/src/observability/telemetry.js +0 -2
- package/src/reranker/cascade-reranker.js +79 -0
- package/src/reranker/embedding-reranker.js +124 -0
- package/src/reranker/llm-reranker.js +6 -3
- package/src/reranker/scoring-reranker.js +123 -0
- package/src/retrieval/bm25-search.js +157 -0
- package/src/retrieval/hybrid-retriever.js +111 -0
- package/src/retrieval/rank-fusion.js +62 -0
- package/src/security/jwt-config.js +4 -3
- package/src/security/jwt-validator.js +2 -1
- package/src/security/plugin-sandbox.js +0 -3
- package/src/security/plugin-signature-verifier.js +4 -6
- package/src/security/validator.js +0 -2
- package/src/streaming/embedding-stream.js +197 -0
- package/src/streaming/sse-adapter.js +168 -0
- package/src/streaming/stream-router.js +210 -0
- package/src/streaming/streaming-embedder.js +231 -0
- package/src/streaming/websocket-adapter.js +171 -0
- package/src/templates/scaffold.js +147 -0
- package/src/templates/template-registry.js +272 -0
- package/src/utils/contract-validator.js +2 -1
- package/src/utils/input-sanitizer.js +80 -99
- package/src/utils/performance-monitor.js +0 -3
- package/src/utils/plugin-scaffolder.js +9 -16
- package/src/utils/rate-limiter.js +0 -1
- package/src/utils/retry-policy.js +0 -3
- package/src/utils/safe-expression-evaluator.js +0 -3
- package/src/utils/secure-logger-config.js +2 -4
- package/src/utils/secure-logging.js +0 -3
- package/src/utils/structured-logger.js +0 -3
- package/src/ai/index-fixed.js +0 -509
- package/src/ai/module-template.js +0 -37
- package/src/ci/workflow-analyzer.js +0 -71
- package/src/cli/plugin-marketplace-commands.js +0 -869
- package/src/dev/README.md +0 -126
- package/src/dev/examples/hot-reload-usage.js +0 -355
- package/src/mocks/openai-embedder.js +0 -119
- package/src/mocks/openai-llm.js +0 -77
- package/src/mocks/pdf-loader.js +0 -21
- package/src/mocks/pinecone-retriever.js +0 -106
- package/src/scripts/script-utilities.js +0 -36
- package/src/utils/ci/diagnostic-reporter.js +0 -57
- package/src/utils/examples/error-formatter-usage.js +0 -351
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @module templates/scaffold
|
|
5
|
+
* @description Creates complete project directories from templates.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { EventEmitter } = require('events');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const { TemplateRegistry } = require('./template-registry');
|
|
12
|
+
|
|
13
|
+
/** @type {Object} Default configuration for the project scaffolder */
|
|
14
|
+
const DEFAULT_CONFIG = {
|
|
15
|
+
installDependencies: false,
|
|
16
|
+
overwrite: false,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Creates complete project directories from registered templates.
|
|
21
|
+
*
|
|
22
|
+
* @extends EventEmitter
|
|
23
|
+
* @fires ProjectScaffolder#created
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* const scaffolder = new ProjectScaffolder();
|
|
27
|
+
* const result = scaffolder.create('document-qa', '/path/to/my-project');
|
|
28
|
+
* console.log(result.files); // list of created files
|
|
29
|
+
*/
|
|
30
|
+
class ProjectScaffolder extends EventEmitter {
|
|
31
|
+
/**
|
|
32
|
+
* @param {Object} [options={}] - Scaffolder configuration
|
|
33
|
+
* @param {boolean} [options.installDependencies=false] - Whether to auto-run npm install
|
|
34
|
+
* @param {boolean} [options.overwrite=false] - Allow overwriting existing directories
|
|
35
|
+
*/
|
|
36
|
+
constructor(options = {}) {
|
|
37
|
+
super();
|
|
38
|
+
this.config = { ...DEFAULT_CONFIG, ...options };
|
|
39
|
+
this.registry = new TemplateRegistry();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Create a new project from a template.
|
|
44
|
+
*
|
|
45
|
+
* @param {string} templateKey - Key of the template to use
|
|
46
|
+
* @param {string} projectDir - Target directory for the new project
|
|
47
|
+
* @param {Object} [options={}] - Per-call overrides
|
|
48
|
+
* @param {boolean} [options.overwrite] - Override the instance-level overwrite setting
|
|
49
|
+
* @returns {{projectDir: string, files: string[], template: string}} Creation result
|
|
50
|
+
* @throws {Error} If template is not found or directory already exists
|
|
51
|
+
*/
|
|
52
|
+
create(templateKey, projectDir, options = {}) {
|
|
53
|
+
const template = this.registry.get(templateKey);
|
|
54
|
+
if (!template) {
|
|
55
|
+
throw new Error(`Unknown template: "${templateKey}"`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const resolvedDir = path.resolve(projectDir);
|
|
59
|
+
const allowOverwrite =
|
|
60
|
+
options.overwrite !== undefined
|
|
61
|
+
? options.overwrite
|
|
62
|
+
: this.config.overwrite;
|
|
63
|
+
|
|
64
|
+
if (fs.existsSync(resolvedDir) && !allowOverwrite) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
`Directory already exists: ${resolvedDir}. Use overwrite option to replace.`,
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fs.mkdirSync(resolvedDir, { recursive: true });
|
|
71
|
+
|
|
72
|
+
const createdFiles = [];
|
|
73
|
+
|
|
74
|
+
// Write package.json
|
|
75
|
+
const projectName = path.basename(resolvedDir);
|
|
76
|
+
const packageJson = {
|
|
77
|
+
name: projectName,
|
|
78
|
+
version: '1.0.0',
|
|
79
|
+
description: template.description,
|
|
80
|
+
main: 'index.js',
|
|
81
|
+
scripts: {
|
|
82
|
+
start: 'node index.js',
|
|
83
|
+
},
|
|
84
|
+
dependencies: template.dependencies || {},
|
|
85
|
+
devDependencies: template.devDependencies || {},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const packageJsonPath = path.join(resolvedDir, 'package.json');
|
|
89
|
+
fs.writeFileSync(
|
|
90
|
+
packageJsonPath,
|
|
91
|
+
JSON.stringify(packageJson, null, 2) + '\n',
|
|
92
|
+
);
|
|
93
|
+
createdFiles.push('package.json');
|
|
94
|
+
|
|
95
|
+
// Write template files
|
|
96
|
+
const files = template.files || {};
|
|
97
|
+
for (const [fileName, content] of Object.entries(files)) {
|
|
98
|
+
const filePath = path.join(resolvedDir, fileName);
|
|
99
|
+
const fileDir = path.dirname(filePath);
|
|
100
|
+
|
|
101
|
+
if (fileDir !== resolvedDir) {
|
|
102
|
+
fs.mkdirSync(fileDir, { recursive: true });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
fs.writeFileSync(filePath, content + '\n');
|
|
106
|
+
createdFiles.push(fileName);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Write .ragrc.json from template config
|
|
110
|
+
if (template.config) {
|
|
111
|
+
const ragrcPath = path.join(resolvedDir, '.ragrc.json');
|
|
112
|
+
fs.writeFileSync(
|
|
113
|
+
ragrcPath,
|
|
114
|
+
JSON.stringify(template.config, null, 2) + '\n',
|
|
115
|
+
);
|
|
116
|
+
createdFiles.push('.ragrc.json');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const result = {
|
|
120
|
+
projectDir: resolvedDir,
|
|
121
|
+
files: createdFiles,
|
|
122
|
+
template: templateKey,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @event ProjectScaffolder#created
|
|
127
|
+
* @type {Object}
|
|
128
|
+
* @property {string} projectDir - Absolute path to created project
|
|
129
|
+
* @property {string[]} files - List of created file names
|
|
130
|
+
* @property {string} template - Template key that was used
|
|
131
|
+
*/
|
|
132
|
+
this.emit('created', result);
|
|
133
|
+
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* List all available templates.
|
|
139
|
+
*
|
|
140
|
+
* @returns {Array<{key: string, name: string, description: string}>} Available templates
|
|
141
|
+
*/
|
|
142
|
+
listTemplates() {
|
|
143
|
+
return this.registry.list();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
module.exports = { ProjectScaffolder, DEFAULT_CONFIG };
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @module templates/template-registry
|
|
5
|
+
* @description Registry of built-in project templates for RAG pipeline scaffolding.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** @type {Object<string, Object>} Built-in template definitions */
|
|
9
|
+
const TEMPLATES = {
|
|
10
|
+
'document-qa': {
|
|
11
|
+
name: 'Document Q&A',
|
|
12
|
+
description: 'Question answering over documents (PDF, Markdown, HTML)',
|
|
13
|
+
dependencies: { '@devilsdev/rag-pipeline-utils': 'latest' },
|
|
14
|
+
devDependencies: {},
|
|
15
|
+
config: {
|
|
16
|
+
pipeline: {
|
|
17
|
+
loader: 'markdown',
|
|
18
|
+
embedder: 'openai',
|
|
19
|
+
retriever: 'memory',
|
|
20
|
+
llm: 'openai',
|
|
21
|
+
},
|
|
22
|
+
options: { topK: 5, citations: true, evaluate: true },
|
|
23
|
+
},
|
|
24
|
+
files: {
|
|
25
|
+
'index.js': [
|
|
26
|
+
'// Document Q&A Pipeline',
|
|
27
|
+
'const { createRagPipeline, ChunkingEngine } = require(\'@devilsdev/rag-pipeline-utils\');',
|
|
28
|
+
'',
|
|
29
|
+
'// Configure your pipeline',
|
|
30
|
+
'const pipeline = createRagPipeline({',
|
|
31
|
+
' // Add your plugins here',
|
|
32
|
+
' // loader: new YourLoader(),',
|
|
33
|
+
' // embedder: new YourEmbedder({ apiKey: process.env.OPENAI_API_KEY }),',
|
|
34
|
+
' // retriever: new YourRetriever(),',
|
|
35
|
+
' // llm: new YourLLM({ apiKey: process.env.OPENAI_API_KEY }),',
|
|
36
|
+
'});',
|
|
37
|
+
'',
|
|
38
|
+
'async function main() {',
|
|
39
|
+
' const result = await pipeline.run({',
|
|
40
|
+
' query: \'What does this document say?\',',
|
|
41
|
+
' options: { citations: true, evaluate: true },',
|
|
42
|
+
' });',
|
|
43
|
+
' console.log(\'Answer:\', result.answer);',
|
|
44
|
+
' if (result.citations) {',
|
|
45
|
+
' console.log(\'Groundedness:\', result.citations.groundednessScore);',
|
|
46
|
+
' }',
|
|
47
|
+
'}',
|
|
48
|
+
'',
|
|
49
|
+
'main().catch(console.error);',
|
|
50
|
+
].join('\n'),
|
|
51
|
+
'README.md': [
|
|
52
|
+
'# Document Q&A Pipeline',
|
|
53
|
+
'',
|
|
54
|
+
'A RAG pipeline for answering questions about your documents.',
|
|
55
|
+
'',
|
|
56
|
+
'## Setup',
|
|
57
|
+
'',
|
|
58
|
+
'1. Install dependencies: `npm install`',
|
|
59
|
+
'2. Set your API key: `export OPENAI_API_KEY=your-key`',
|
|
60
|
+
'3. Run: `node index.js`',
|
|
61
|
+
].join('\n'),
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
chatbot: {
|
|
65
|
+
name: 'Chatbot',
|
|
66
|
+
description: 'Conversational chatbot with document context',
|
|
67
|
+
dependencies: { '@devilsdev/rag-pipeline-utils': 'latest' },
|
|
68
|
+
devDependencies: {},
|
|
69
|
+
config: {
|
|
70
|
+
pipeline: { embedder: 'openai', retriever: 'memory', llm: 'openai' },
|
|
71
|
+
options: { topK: 3, stream: true },
|
|
72
|
+
},
|
|
73
|
+
files: {
|
|
74
|
+
'index.js': [
|
|
75
|
+
'// Chatbot Pipeline',
|
|
76
|
+
'const { createRagPipeline } = require(\'@devilsdev/rag-pipeline-utils\');',
|
|
77
|
+
'',
|
|
78
|
+
'const pipeline = createRagPipeline({',
|
|
79
|
+
' // Configure your chatbot plugins',
|
|
80
|
+
'});',
|
|
81
|
+
'',
|
|
82
|
+
'async function chat(question) {',
|
|
83
|
+
' const result = await pipeline.run({',
|
|
84
|
+
' query: question,',
|
|
85
|
+
' options: { stream: false },',
|
|
86
|
+
' });',
|
|
87
|
+
' return result.results;',
|
|
88
|
+
'}',
|
|
89
|
+
'',
|
|
90
|
+
'// Example usage',
|
|
91
|
+
'chat(\'Hello, how can you help me?\').then(console.log).catch(console.error);',
|
|
92
|
+
].join('\n'),
|
|
93
|
+
'README.md': [
|
|
94
|
+
'# Chatbot Pipeline',
|
|
95
|
+
'',
|
|
96
|
+
'A conversational RAG chatbot.',
|
|
97
|
+
'',
|
|
98
|
+
'## Setup',
|
|
99
|
+
'',
|
|
100
|
+
'1. `npm install`',
|
|
101
|
+
'2. `export OPENAI_API_KEY=your-key`',
|
|
102
|
+
'3. `node index.js`',
|
|
103
|
+
].join('\n'),
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
'code-search': {
|
|
107
|
+
name: 'Code Search',
|
|
108
|
+
description: 'Search and explain code repositories',
|
|
109
|
+
dependencies: { '@devilsdev/rag-pipeline-utils': 'latest' },
|
|
110
|
+
devDependencies: {},
|
|
111
|
+
config: {
|
|
112
|
+
pipeline: {
|
|
113
|
+
loader: 'directory',
|
|
114
|
+
embedder: 'openai',
|
|
115
|
+
retriever: 'memory',
|
|
116
|
+
llm: 'openai',
|
|
117
|
+
},
|
|
118
|
+
options: { topK: 10 },
|
|
119
|
+
},
|
|
120
|
+
files: {
|
|
121
|
+
'index.js': [
|
|
122
|
+
'// Code Search Pipeline',
|
|
123
|
+
'const { createRagPipeline, ChunkingEngine } = require(\'@devilsdev/rag-pipeline-utils\');',
|
|
124
|
+
'',
|
|
125
|
+
'const chunker = new ChunkingEngine({ strategy: \'structure-aware\', chunkSize: 1024 });',
|
|
126
|
+
'',
|
|
127
|
+
'const pipeline = createRagPipeline({',
|
|
128
|
+
' // Configure for code search',
|
|
129
|
+
'});',
|
|
130
|
+
'',
|
|
131
|
+
'async function searchCode(query) {',
|
|
132
|
+
' const result = await pipeline.run({ query, options: { topK: 10 } });',
|
|
133
|
+
' return result.results;',
|
|
134
|
+
'}',
|
|
135
|
+
'',
|
|
136
|
+
'searchCode(\'How does authentication work?\').then(console.log).catch(console.error);',
|
|
137
|
+
].join('\n'),
|
|
138
|
+
'README.md': [
|
|
139
|
+
'# Code Search Pipeline',
|
|
140
|
+
'',
|
|
141
|
+
'Search and explain code in your repository.',
|
|
142
|
+
'',
|
|
143
|
+
'## Setup',
|
|
144
|
+
'',
|
|
145
|
+
'1. `npm install`',
|
|
146
|
+
'2. `export OPENAI_API_KEY=your-key`',
|
|
147
|
+
'3. `node index.js`',
|
|
148
|
+
].join('\n'),
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
'customer-support': {
|
|
152
|
+
name: 'Customer Support',
|
|
153
|
+
description: 'AI-powered customer support with knowledge base',
|
|
154
|
+
dependencies: { '@devilsdev/rag-pipeline-utils': 'latest' },
|
|
155
|
+
devDependencies: {},
|
|
156
|
+
config: {
|
|
157
|
+
pipeline: {
|
|
158
|
+
loader: 'markdown',
|
|
159
|
+
embedder: 'openai',
|
|
160
|
+
retriever: 'memory',
|
|
161
|
+
llm: 'openai',
|
|
162
|
+
},
|
|
163
|
+
options: { topK: 5, citations: true, guardrails: true },
|
|
164
|
+
},
|
|
165
|
+
files: {
|
|
166
|
+
'index.js': [
|
|
167
|
+
'// Customer Support Pipeline',
|
|
168
|
+
'const { createRagPipeline, GuardrailsPipeline } = require(\'@devilsdev/rag-pipeline-utils\');',
|
|
169
|
+
'',
|
|
170
|
+
'const basePipeline = createRagPipeline({',
|
|
171
|
+
' // Configure your support pipeline',
|
|
172
|
+
'});',
|
|
173
|
+
'',
|
|
174
|
+
'// Wrap with guardrails for production safety',
|
|
175
|
+
'const pipeline = new GuardrailsPipeline(basePipeline, {',
|
|
176
|
+
' preRetrieval: { enableInjectionDetection: true },',
|
|
177
|
+
' postGeneration: { enablePIIDetection: true, enableGroundednessCheck: true },',
|
|
178
|
+
'});',
|
|
179
|
+
'',
|
|
180
|
+
'async function handleTicket(question) {',
|
|
181
|
+
' const result = await pipeline.run({ query: question });',
|
|
182
|
+
' return { answer: result.answer, sources: result.citations, safe: result.guardrails };',
|
|
183
|
+
'}',
|
|
184
|
+
'',
|
|
185
|
+
'handleTicket(\'How do I reset my password?\').then(console.log).catch(console.error);',
|
|
186
|
+
].join('\n'),
|
|
187
|
+
'README.md': [
|
|
188
|
+
'# Customer Support Pipeline',
|
|
189
|
+
'',
|
|
190
|
+
'AI-powered support with guardrails and citations.',
|
|
191
|
+
'',
|
|
192
|
+
'## Setup',
|
|
193
|
+
'',
|
|
194
|
+
'1. `npm install`',
|
|
195
|
+
'2. `export OPENAI_API_KEY=your-key`',
|
|
196
|
+
'3. `node index.js`',
|
|
197
|
+
].join('\n'),
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Registry of built-in and custom project templates.
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* const registry = new TemplateRegistry();
|
|
207
|
+
* const templates = registry.list();
|
|
208
|
+
* const template = registry.get('document-qa');
|
|
209
|
+
*/
|
|
210
|
+
class TemplateRegistry {
|
|
211
|
+
constructor() {
|
|
212
|
+
/** @type {Map<string, Object>} */
|
|
213
|
+
this.templates = new Map(Object.entries(TEMPLATES));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* List all available templates.
|
|
218
|
+
*
|
|
219
|
+
* @returns {Array<{key: string, name: string, description: string}>} Summary of each template
|
|
220
|
+
*/
|
|
221
|
+
list() {
|
|
222
|
+
return Array.from(this.templates.entries()).map(([key, t]) => ({
|
|
223
|
+
key,
|
|
224
|
+
name: t.name,
|
|
225
|
+
description: t.description,
|
|
226
|
+
}));
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Get a full template definition by key.
|
|
231
|
+
*
|
|
232
|
+
* @param {string} templateKey - Template identifier
|
|
233
|
+
* @returns {Object|null} Full template object, or null if not found
|
|
234
|
+
*/
|
|
235
|
+
get(templateKey) {
|
|
236
|
+
return this.templates.get(templateKey) || null;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Register a custom template.
|
|
241
|
+
*
|
|
242
|
+
* @param {string} key - Template identifier
|
|
243
|
+
* @param {Object} template - Template definition
|
|
244
|
+
* @param {string} template.name - Display name
|
|
245
|
+
* @param {string} template.description - Short description
|
|
246
|
+
* @param {Object} template.dependencies - npm dependencies
|
|
247
|
+
* @param {Object} template.config - Pipeline configuration
|
|
248
|
+
* @param {Object} template.files - Map of filename to file content
|
|
249
|
+
* @returns {void}
|
|
250
|
+
*/
|
|
251
|
+
register(key, template) {
|
|
252
|
+
if (!key || typeof key !== 'string') {
|
|
253
|
+
throw new TypeError('Template key must be a non-empty string');
|
|
254
|
+
}
|
|
255
|
+
if (!template || !template.name || !template.files) {
|
|
256
|
+
throw new TypeError('Template must have a name and files');
|
|
257
|
+
}
|
|
258
|
+
this.templates.set(key, template);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Check if a template exists.
|
|
263
|
+
*
|
|
264
|
+
* @param {string} key - Template identifier
|
|
265
|
+
* @returns {boolean} Whether the template is registered
|
|
266
|
+
*/
|
|
267
|
+
has(key) {
|
|
268
|
+
return this.templates.has(key);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
module.exports = { TemplateRegistry, TEMPLATES };
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
const fs = require('fs');
|
|
17
17
|
const path = require('path');
|
|
18
|
+
const { logger } = require('./logger');
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* ContractValidator class for validating plugin implementations
|
|
@@ -107,7 +108,7 @@ class ContractValidator {
|
|
|
107
108
|
contracts[type] = this.loadContract(type);
|
|
108
109
|
} catch (error) {
|
|
109
110
|
// Skip invalid contracts
|
|
110
|
-
|
|
111
|
+
logger.warn(`Skipping invalid contract: ${file}`);
|
|
111
112
|
}
|
|
112
113
|
}
|
|
113
114
|
}
|
|
@@ -313,118 +313,99 @@ class InputSanitizer {
|
|
|
313
313
|
}
|
|
314
314
|
|
|
315
315
|
// Check cache
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
this.cacheAccessTimes.set(cacheKey, Date.now());
|
|
320
|
-
this.stats.cached++;
|
|
321
|
-
return this.cache.get(cacheKey);
|
|
322
|
-
}
|
|
316
|
+
const cached = this._getCachedResult(rule, str);
|
|
317
|
+
if (cached !== undefined) {
|
|
318
|
+
return cached;
|
|
323
319
|
}
|
|
324
320
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
switch (rule) {
|
|
328
|
-
case SanitizationRules.NONE:
|
|
329
|
-
result = str;
|
|
330
|
-
break;
|
|
331
|
-
|
|
332
|
-
case SanitizationRules.HTML:
|
|
333
|
-
result = this._escapeHtml(str);
|
|
334
|
-
break;
|
|
335
|
-
|
|
336
|
-
case SanitizationRules.HTML_STRICT:
|
|
337
|
-
result = this._stripHtml(str);
|
|
338
|
-
break;
|
|
339
|
-
|
|
340
|
-
case SanitizationRules.XSS:
|
|
341
|
-
result = this._sanitizeXss(str);
|
|
342
|
-
break;
|
|
343
|
-
|
|
344
|
-
case SanitizationRules.SQL:
|
|
345
|
-
result = this._sanitizeSql(str);
|
|
346
|
-
break;
|
|
347
|
-
|
|
348
|
-
case SanitizationRules.COMMAND:
|
|
349
|
-
result = this._sanitizeCommand(str);
|
|
350
|
-
break;
|
|
351
|
-
|
|
352
|
-
case SanitizationRules.PATH:
|
|
353
|
-
result = this._sanitizePath(str);
|
|
354
|
-
break;
|
|
355
|
-
|
|
356
|
-
case SanitizationRules.URL:
|
|
357
|
-
result = this._validateAndSanitizeUrl(str);
|
|
358
|
-
break;
|
|
359
|
-
|
|
360
|
-
case SanitizationRules.EMAIL:
|
|
361
|
-
result = this._validateEmail(str);
|
|
362
|
-
break;
|
|
321
|
+
const result = this._applyRule(str, rule);
|
|
363
322
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
result = this._validateUuid(str);
|
|
370
|
-
break;
|
|
371
|
-
|
|
372
|
-
case SanitizationRules.INTEGER:
|
|
373
|
-
result = this._validateInteger(str);
|
|
374
|
-
break;
|
|
375
|
-
|
|
376
|
-
case SanitizationRules.FLOAT:
|
|
377
|
-
result = this._validateFloat(str);
|
|
378
|
-
break;
|
|
379
|
-
|
|
380
|
-
case SanitizationRules.BOOLEAN:
|
|
381
|
-
result = this._validateBoolean(str);
|
|
382
|
-
break;
|
|
383
|
-
|
|
384
|
-
case SanitizationRules.JSON:
|
|
385
|
-
result = this._validateJson(str);
|
|
386
|
-
break;
|
|
387
|
-
|
|
388
|
-
case SanitizationRules.BASE64:
|
|
389
|
-
result = this._validateBase64(str);
|
|
390
|
-
break;
|
|
323
|
+
// Cache result
|
|
324
|
+
if (this.options.enableCache) {
|
|
325
|
+
const cacheKey = `${rule}:${str}`;
|
|
326
|
+
this._addToCache(cacheKey, result);
|
|
327
|
+
}
|
|
391
328
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
break;
|
|
329
|
+
return result;
|
|
330
|
+
}
|
|
395
331
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
332
|
+
/**
|
|
333
|
+
* Retrieve a previously cached sanitization result.
|
|
334
|
+
* @param {string} rule - The sanitization rule that was applied
|
|
335
|
+
* @param {string} str - The original input string
|
|
336
|
+
* @returns {*} The cached result, or undefined if not cached
|
|
337
|
+
* @private
|
|
338
|
+
*/
|
|
339
|
+
_getCachedResult(rule, str) {
|
|
340
|
+
if (!this.options.enableCache) {
|
|
341
|
+
return undefined;
|
|
342
|
+
}
|
|
399
343
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
344
|
+
const cacheKey = `${rule}:${str}`;
|
|
345
|
+
if (this.cache.has(cacheKey)) {
|
|
346
|
+
this.cacheAccessTimes.set(cacheKey, Date.now());
|
|
347
|
+
this.stats.cached++;
|
|
348
|
+
return this.cache.get(cacheKey);
|
|
349
|
+
}
|
|
403
350
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
break;
|
|
351
|
+
return undefined;
|
|
352
|
+
}
|
|
407
353
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
354
|
+
/**
|
|
355
|
+
* Apply a sanitization or validation rule to an input string.
|
|
356
|
+
* Dispatches to the appropriate handler based on the rule name.
|
|
357
|
+
* @param {string} str - The input string to sanitize
|
|
358
|
+
* @param {string} rule - The sanitization rule to apply
|
|
359
|
+
* @returns {*} The sanitized or validated result
|
|
360
|
+
* @private
|
|
361
|
+
*/
|
|
362
|
+
_applyRule(str, rule) {
|
|
363
|
+
const ruleHandlers = this._getRuleHandlers();
|
|
364
|
+
const handler = ruleHandlers[rule];
|
|
411
365
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
if (this.options.customRules[rule]) {
|
|
415
|
-
result = this.options.customRules[rule](str);
|
|
416
|
-
} else {
|
|
417
|
-
result = this._escapeHtml(str); // Default to HTML escape
|
|
418
|
-
}
|
|
366
|
+
if (handler) {
|
|
367
|
+
return handler(str);
|
|
419
368
|
}
|
|
420
369
|
|
|
421
|
-
//
|
|
422
|
-
if (this.options.
|
|
423
|
-
|
|
424
|
-
this._addToCache(cacheKey, result);
|
|
370
|
+
// Check custom rules
|
|
371
|
+
if (this.options.customRules[rule]) {
|
|
372
|
+
return this.options.customRules[rule](str);
|
|
425
373
|
}
|
|
426
374
|
|
|
427
|
-
|
|
375
|
+
// Default to HTML escape
|
|
376
|
+
return this._escapeHtml(str);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Build the mapping from sanitization rule names to their handler functions.
|
|
381
|
+
* @returns {Object.<string, Function>} Map of rule name to handler function
|
|
382
|
+
* @private
|
|
383
|
+
*/
|
|
384
|
+
_getRuleHandlers() {
|
|
385
|
+
return {
|
|
386
|
+
[SanitizationRules.NONE]: (str) => str,
|
|
387
|
+
[SanitizationRules.HTML]: (str) => this._escapeHtml(str),
|
|
388
|
+
[SanitizationRules.HTML_STRICT]: (str) => this._stripHtml(str),
|
|
389
|
+
[SanitizationRules.XSS]: (str) => this._sanitizeXss(str),
|
|
390
|
+
[SanitizationRules.SQL]: (str) => this._sanitizeSql(str),
|
|
391
|
+
[SanitizationRules.COMMAND]: (str) => this._sanitizeCommand(str),
|
|
392
|
+
[SanitizationRules.PATH]: (str) => this._sanitizePath(str),
|
|
393
|
+
[SanitizationRules.URL]: (str) => this._validateAndSanitizeUrl(str),
|
|
394
|
+
[SanitizationRules.EMAIL]: (str) => this._validateEmail(str),
|
|
395
|
+
[SanitizationRules.ALPHANUMERIC]: (str) =>
|
|
396
|
+
this._validateAlphanumeric(str),
|
|
397
|
+
[SanitizationRules.UUID]: (str) => this._validateUuid(str),
|
|
398
|
+
[SanitizationRules.INTEGER]: (str) => this._validateInteger(str),
|
|
399
|
+
[SanitizationRules.FLOAT]: (str) => this._validateFloat(str),
|
|
400
|
+
[SanitizationRules.BOOLEAN]: (str) => this._validateBoolean(str),
|
|
401
|
+
[SanitizationRules.JSON]: (str) => this._validateJson(str),
|
|
402
|
+
[SanitizationRules.BASE64]: (str) => this._validateBase64(str),
|
|
403
|
+
[SanitizationRules.HEX]: (str) => this._validateHex(str),
|
|
404
|
+
[SanitizationRules.SLUG]: (str) => this._validateSlug(str),
|
|
405
|
+
[SanitizationRules.DOMAIN]: (str) => this._validateDomain(str),
|
|
406
|
+
[SanitizationRules.IPV4]: (str) => this._validateIpv4(str),
|
|
407
|
+
[SanitizationRules.IPV6]: (str) => this._validateIpv6(str),
|
|
408
|
+
};
|
|
428
409
|
}
|
|
429
410
|
|
|
430
411
|
/**
|
|
@@ -11,6 +11,7 @@ const path = require('path');
|
|
|
11
11
|
// eslint-disable-line global-require
|
|
12
12
|
const { pluginContracts } = require('../core/plugin-contracts.js');
|
|
13
13
|
// eslint-disable-line global-require
|
|
14
|
+
const { logger } = require('./logger');
|
|
14
15
|
|
|
15
16
|
class PluginScaffolder {
|
|
16
17
|
constructor(_options = {}) {
|
|
@@ -47,24 +48,16 @@ class PluginScaffolder {
|
|
|
47
48
|
await this.generateReadme(pluginDir, pluginType, pluginName, _options);
|
|
48
49
|
await this.generatePackageJson(pluginDir, pluginType, pluginName, _options);
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
// eslint-disable-line no-console
|
|
56
|
-
console.log(` - __tests__/${pluginName}-${pluginType}.test.js (tests)`);
|
|
57
|
-
// eslint-disable-line no-console
|
|
58
|
-
console.log(
|
|
51
|
+
logger.info(`Plugin scaffolded successfully at: ${pluginDir}`);
|
|
52
|
+
logger.info('Generated files:');
|
|
53
|
+
logger.info(` - src/${pluginName}-${pluginType}.js (main plugin)`);
|
|
54
|
+
logger.info(` - __tests__/${pluginName}-${pluginType}.test.js (tests)`);
|
|
55
|
+
logger.info(
|
|
59
56
|
` - mocks/${pluginName}-${pluginType}-mock.js (mock implementation)`,
|
|
60
57
|
);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
console.log(' - README.md (documentation)');
|
|
65
|
-
// eslint-disable-line no-console
|
|
66
|
-
console.log(' - package.json (npm package)');
|
|
67
|
-
// eslint-disable-line no-console
|
|
58
|
+
logger.info(' - .ragrc.example.json (configuration example)');
|
|
59
|
+
logger.info(' - README.md (documentation)');
|
|
60
|
+
logger.info(' - package.json (npm package)');
|
|
68
61
|
}
|
|
69
62
|
|
|
70
63
|
/**
|