agentic-flow 3.1.0 → 3.2.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/.agents/skills/agentic-flow-ecosystem/SKILL.md +50 -0
- package/.claude/skills/agentic-flow-ecosystem/skill.md +58 -0
- package/.claude/skills/agentic-flow-quickstart/skill.md +6 -6
- package/.claude/skills/hooks-automation/skill.md +11 -11
- package/.claude/skills/memory-patterns/skill.md +7 -7
- package/.claude/skills/sparc-methodology/skill.md +13 -13
- package/.claude/skills/swarm-coordination/skill.md +5 -5
- package/.claude/skills/worker-benchmarks/skill.md +5 -5
- package/.claude/skills/worker-integration/skill.md +5 -5
- package/CHANGELOG.md +25 -0
- package/README.md +82 -67
- package/dist/.tsbuildinfo +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +9 -0
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/core/agentdb-fast.d.ts +21 -11
- package/dist/core/agentdb-fast.d.ts.map +1 -1
- package/dist/core/agentdb-fast.js +39 -14
- package/dist/core/agentdb-fast.js.map +1 -1
- package/dist/integrations/agent-booster.d.ts +35 -0
- package/dist/integrations/agent-booster.d.ts.map +1 -0
- package/dist/integrations/agent-booster.js +45 -0
- package/dist/integrations/agent-booster.js.map +1 -0
- package/dist/integrations/index.d.ts +15 -0
- package/dist/integrations/index.d.ts.map +1 -0
- package/dist/integrations/index.js +11 -0
- package/dist/integrations/index.js.map +1 -0
- package/dist/integrations/onnx-wasm-embedder.d.ts +59 -0
- package/dist/integrations/onnx-wasm-embedder.d.ts.map +1 -0
- package/dist/integrations/onnx-wasm-embedder.js +145 -0
- package/dist/integrations/onnx-wasm-embedder.js.map +1 -0
- package/dist/integrations/optional.d.ts +44 -0
- package/dist/integrations/optional.d.ts.map +1 -0
- package/dist/integrations/optional.js +107 -0
- package/dist/integrations/optional.js.map +1 -0
- package/dist/integrations/prompt-injection.d.ts +52 -0
- package/dist/integrations/prompt-injection.d.ts.map +1 -0
- package/dist/integrations/prompt-injection.js +126 -0
- package/dist/integrations/prompt-injection.js.map +1 -0
- package/dist/integrations/sublinear.d.ts +71 -0
- package/dist/integrations/sublinear.d.ts.map +1 -0
- package/dist/integrations/sublinear.js +227 -0
- package/dist/integrations/sublinear.js.map +1 -0
- package/dist/integrations/task-partition.d.ts +40 -0
- package/dist/integrations/task-partition.d.ts.map +1 -0
- package/dist/integrations/task-partition.js +173 -0
- package/dist/integrations/task-partition.js.map +1 -0
- package/dist/mcp/mcp-policy.d.ts.map +1 -1
- package/dist/mcp/mcp-policy.js +2 -0
- package/dist/mcp/mcp-policy.js.map +1 -1
- package/dist/mcp/standalone-stdio.js +12 -26
- package/dist/mcp/standalone-stdio.js.map +1 -1
- package/dist/mcp/tools/ecosystem-tools.d.ts +49 -0
- package/dist/mcp/tools/ecosystem-tools.d.ts.map +1 -0
- package/dist/mcp/tools/ecosystem-tools.js +126 -0
- package/dist/mcp/tools/ecosystem-tools.js.map +1 -0
- package/dist/routing/SemanticRouter.d.ts +25 -9
- package/dist/routing/SemanticRouter.d.ts.map +1 -1
- package/dist/routing/SemanticRouter.js +63 -12
- package/dist/routing/SemanticRouter.js.map +1 -1
- package/dist/utils/input-validator.d.ts +10 -2
- package/dist/utils/input-validator.d.ts.map +1 -1
- package/dist/utils/input-validator.js +30 -2
- package/dist/utils/input-validator.js.map +1 -1
- package/dist/utils/model-cache.d.ts.map +1 -1
- package/dist/utils/model-cache.js +6 -25
- package/dist/utils/model-cache.js.map +1 -1
- package/dist/wasm/onnx-embeddings-wasm.d.ts.map +1 -1
- package/dist/wasm/onnx-embeddings-wasm.js +21 -10
- package/dist/wasm/onnx-embeddings-wasm.js.map +1 -1
- package/docs/integrations/FASTMCP_CLI_INTEGRATION.md +1 -1
- package/package.json +12 -7
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Semantic Router - HNSW-Powered Intent Matching
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Uses @ruvector/router's native HNSW index (VectorDb) when the package and
|
|
5
|
+
* its platform binary are installed, and an exact brute-force cosine scan
|
|
6
|
+
* otherwise. Both return the same ranking contract: similarity in [-1, 1],
|
|
7
|
+
* highest first.
|
|
5
8
|
*
|
|
6
9
|
* Features:
|
|
7
10
|
* - HNSW (Hierarchical Navigable Small World) index
|
|
@@ -17,6 +20,7 @@
|
|
|
17
20
|
* - O(log N) search complexity
|
|
18
21
|
*/
|
|
19
22
|
import type { EmbeddingService } from 'agentdb';
|
|
23
|
+
export type SemanticIndexBackend = 'ruvector-router' | 'brute-force';
|
|
20
24
|
export interface AgentIntent {
|
|
21
25
|
/** Agent type identifier */
|
|
22
26
|
agentType: string;
|
|
@@ -73,8 +77,17 @@ export declare class SemanticRouter {
|
|
|
73
77
|
private agentIntents;
|
|
74
78
|
private intentEmbeddings;
|
|
75
79
|
private indexBuilt;
|
|
80
|
+
private nativeIndex;
|
|
81
|
+
private backend;
|
|
82
|
+
private readonly useNative;
|
|
76
83
|
private routingStats;
|
|
77
|
-
|
|
84
|
+
/**
|
|
85
|
+
* @param embedder - Embedding service for intents and tasks
|
|
86
|
+
* @param options.native - Use @ruvector/router when installed (default true)
|
|
87
|
+
*/
|
|
88
|
+
constructor(embedder: EmbeddingService, options?: {
|
|
89
|
+
native?: boolean;
|
|
90
|
+
});
|
|
78
91
|
/**
|
|
79
92
|
* Register agent intent for routing
|
|
80
93
|
*
|
|
@@ -88,12 +101,15 @@ export declare class SemanticRouter {
|
|
|
88
101
|
*/
|
|
89
102
|
registerAgents(intents: AgentIntent[]): Promise<void>;
|
|
90
103
|
/**
|
|
91
|
-
* Build
|
|
104
|
+
* Build the routing index.
|
|
92
105
|
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
106
|
+
* Loads @ruvector/router's native HNSW (VectorDb, cosine metric) when it is
|
|
107
|
+
* installed; otherwise routing uses an exact brute-force scan, which is
|
|
108
|
+
* still fast at the ~66-agent scale.
|
|
95
109
|
*/
|
|
96
110
|
buildIndex(): void;
|
|
111
|
+
/** Which index answered the last build: native HNSW or brute force. */
|
|
112
|
+
getIndexBackend(): SemanticIndexBackend;
|
|
97
113
|
/**
|
|
98
114
|
* Route task to best agent using semantic similarity
|
|
99
115
|
*
|
|
@@ -130,14 +146,14 @@ export declare class SemanticRouter {
|
|
|
130
146
|
*/
|
|
131
147
|
getRegisteredAgents(): AgentIntent[];
|
|
132
148
|
/**
|
|
133
|
-
* Search
|
|
149
|
+
* Search the index for nearest neighbours.
|
|
134
150
|
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
151
|
+
* @ruvector/router reports cosine *distance* (0 = identical), so it is
|
|
152
|
+
* converted to similarity (1 - distance) to keep "higher is better".
|
|
137
153
|
*
|
|
138
154
|
* @param queryEmbedding - Query vector
|
|
139
155
|
* @param k - Number of results
|
|
140
|
-
* @returns Top k candidates with similarity scores
|
|
156
|
+
* @returns Top k candidates with similarity scores, highest first
|
|
141
157
|
*/
|
|
142
158
|
private searchHNSW;
|
|
143
159
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SemanticRouter.d.ts","sourceRoot":"","sources":["../../src/routing/SemanticRouter.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"SemanticRouter.d.ts","sourceRoot":"","sources":["../../src/routing/SemanticRouter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Semantic Router - HNSW-Powered Intent Matching
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Uses @ruvector/router's native HNSW index (VectorDb) when the package and
|
|
5
|
+
* its platform binary are installed, and an exact brute-force cosine scan
|
|
6
|
+
* otherwise. Both return the same ranking contract: similarity in [-1, 1],
|
|
7
|
+
* highest first.
|
|
5
8
|
*
|
|
6
9
|
* Features:
|
|
7
10
|
* - HNSW (Hierarchical Navigable Small World) index
|
|
@@ -16,6 +19,7 @@
|
|
|
16
19
|
* - Support for 66+ agent types
|
|
17
20
|
* - O(log N) search complexity
|
|
18
21
|
*/
|
|
22
|
+
import { requireOptional } from '../integrations/optional.js';
|
|
19
23
|
/**
|
|
20
24
|
* Semantic Router
|
|
21
25
|
*
|
|
@@ -30,12 +34,20 @@ export class SemanticRouter {
|
|
|
30
34
|
// Agent registry
|
|
31
35
|
agentIntents;
|
|
32
36
|
intentEmbeddings;
|
|
33
|
-
// HNSW index
|
|
37
|
+
// Native HNSW index (@ruvector/router) or null for the brute-force scan
|
|
34
38
|
indexBuilt = false;
|
|
39
|
+
nativeIndex = null;
|
|
40
|
+
backend = 'brute-force';
|
|
41
|
+
useNative;
|
|
35
42
|
// Performance tracking
|
|
36
43
|
routingStats;
|
|
37
|
-
|
|
44
|
+
/**
|
|
45
|
+
* @param embedder - Embedding service for intents and tasks
|
|
46
|
+
* @param options.native - Use @ruvector/router when installed (default true)
|
|
47
|
+
*/
|
|
48
|
+
constructor(embedder, options = {}) {
|
|
38
49
|
this.embedder = embedder;
|
|
50
|
+
this.useNative = options.native ?? true;
|
|
39
51
|
this.agentIntents = new Map();
|
|
40
52
|
this.intentEmbeddings = new Map();
|
|
41
53
|
this.routingStats = {
|
|
@@ -71,16 +83,43 @@ export class SemanticRouter {
|
|
|
71
83
|
await Promise.all(intents.map(intent => this.registerAgent(intent)));
|
|
72
84
|
}
|
|
73
85
|
/**
|
|
74
|
-
* Build
|
|
86
|
+
* Build the routing index.
|
|
75
87
|
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
88
|
+
* Loads @ruvector/router's native HNSW (VectorDb, cosine metric) when it is
|
|
89
|
+
* installed; otherwise routing uses an exact brute-force scan, which is
|
|
90
|
+
* still fast at the ~66-agent scale.
|
|
78
91
|
*/
|
|
79
92
|
buildIndex() {
|
|
80
|
-
|
|
81
|
-
|
|
93
|
+
this.nativeIndex = null;
|
|
94
|
+
this.backend = 'brute-force';
|
|
95
|
+
const first = this.intentEmbeddings.values().next().value;
|
|
96
|
+
const router = this.useNative && first
|
|
97
|
+
? requireOptional('@ruvector/router')
|
|
98
|
+
: null;
|
|
99
|
+
if (router && first) {
|
|
100
|
+
try {
|
|
101
|
+
const db = new router.VectorDb({
|
|
102
|
+
dimensions: first.length,
|
|
103
|
+
distanceMetric: router.DistanceMetric.Cosine,
|
|
104
|
+
});
|
|
105
|
+
for (const [agentType, embedding] of Array.from(this.intentEmbeddings.entries())) {
|
|
106
|
+
db.insert(agentType, embedding instanceof Float32Array ? embedding : Float32Array.from(embedding));
|
|
107
|
+
}
|
|
108
|
+
this.nativeIndex = db;
|
|
109
|
+
this.backend = 'ruvector-router';
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// Native binary missing for this platform, or a dimension mismatch:
|
|
113
|
+
// keep the exact brute-force path.
|
|
114
|
+
this.nativeIndex = null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
82
117
|
this.indexBuilt = true;
|
|
83
118
|
}
|
|
119
|
+
/** Which index answered the last build: native HNSW or brute force. */
|
|
120
|
+
getIndexBackend() {
|
|
121
|
+
return this.backend;
|
|
122
|
+
}
|
|
84
123
|
/**
|
|
85
124
|
* Route task to best agent using semantic similarity
|
|
86
125
|
*
|
|
@@ -194,16 +233,28 @@ export class SemanticRouter {
|
|
|
194
233
|
// Private Helper Methods
|
|
195
234
|
// ========================================================================
|
|
196
235
|
/**
|
|
197
|
-
* Search
|
|
236
|
+
* Search the index for nearest neighbours.
|
|
198
237
|
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
238
|
+
* @ruvector/router reports cosine *distance* (0 = identical), so it is
|
|
239
|
+
* converted to similarity (1 - distance) to keep "higher is better".
|
|
201
240
|
*
|
|
202
241
|
* @param queryEmbedding - Query vector
|
|
203
242
|
* @param k - Number of results
|
|
204
|
-
* @returns Top k candidates with similarity scores
|
|
243
|
+
* @returns Top k candidates with similarity scores, highest first
|
|
205
244
|
*/
|
|
206
245
|
searchHNSW(queryEmbedding, k) {
|
|
246
|
+
if (this.nativeIndex) {
|
|
247
|
+
try {
|
|
248
|
+
const query = queryEmbedding instanceof Float32Array ? queryEmbedding : Float32Array.from(queryEmbedding);
|
|
249
|
+
return this.nativeIndex
|
|
250
|
+
.search(query, Math.min(k, this.intentEmbeddings.size))
|
|
251
|
+
.map((r) => ({ agentType: r.id, similarity: 1 - r.score }))
|
|
252
|
+
.sort((a, b) => b.similarity - a.similarity);
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
// fall through to the exact scan
|
|
256
|
+
}
|
|
257
|
+
}
|
|
207
258
|
const candidates = [];
|
|
208
259
|
for (const [agentType, embedding] of Array.from(this.intentEmbeddings.entries())) {
|
|
209
260
|
const similarity = this.cosineSimilarity(queryEmbedding, embedding);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SemanticRouter.js","sourceRoot":"","sources":["../../src/routing/SemanticRouter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Semantic Router - HNSW-Powered Intent Matching\n *\n * Integrates @ruvector/router for sub-10ms semantic routing.\n *\n * Features:\n * - HNSW (Hierarchical Navigable Small World) index\n * - Intent classification for 66+ agents\n * - Sub-10ms routing latency\n * - Automatic intent embedding and indexing\n * - Multi-intent detection\n *\n * Performance:\n * - <10ms routing time\n * - >85% routing accuracy\n * - Support for 66+ agent types\n * - O(log N) search complexity\n */\n\n// Import from agentdb package\nimport type { EmbeddingService } from 'agentdb';\n\nexport interface AgentIntent {\n /** Agent type identifier */\n agentType: string;\n /** Natural language description of agent capabilities */\n description: string;\n /** Example tasks for this agent */\n examples: string[];\n /** Agent specialty tags */\n tags: string[];\n}\n\nexport interface RoutingResult {\n /** Primary agent selection */\n primaryAgent: string;\n /** Confidence score (0-1) */\n confidence: number;\n /** Secondary agent suggestions */\n alternatives: Array<{\n agentType: string;\n confidence: number;\n }>;\n /** Matched intent descriptions */\n matchedIntents: string[];\n /** Routing metrics */\n metrics: {\n routingTimeMs: number;\n embeddingTimeMs: number;\n searchTimeMs: number;\n candidatesEvaluated: number;\n };\n}\n\nexport interface MultiIntentResult {\n /** Detected intents in order of confidence */\n intents: Array<{\n agentType: string;\n confidence: number;\n matchedText: string;\n }>;\n /** Whether task requires multiple agents */\n requiresMultiAgent: boolean;\n /** Suggested execution order */\n executionOrder: string[];\n}\n\n/**\n * Semantic Router\n *\n * Provides intent-based agent routing:\n * 1. Register agent intents with descriptions\n * 2. Build HNSW index for fast semantic search\n * 3. Route tasks to agents based on intent similarity\n * 4. Support multi-intent detection for complex tasks\n */\nexport class SemanticRouter {\n private embedder: EmbeddingService;\n\n // Agent registry\n private agentIntents: Map<string, AgentIntent>;\n private intentEmbeddings: Map<string, Float32Array>;\n\n // HNSW index simulation (production would use @ruvector/router)\n private indexBuilt: boolean = false;\n\n // Performance tracking\n private routingStats: {\n totalRoutes: number;\n avgRoutingTimeMs: number;\n accuracyRate: number; // Requires feedback\n };\n\n constructor(embedder: EmbeddingService) {\n this.embedder = embedder;\n this.agentIntents = new Map();\n this.intentEmbeddings = new Map();\n this.routingStats = {\n totalRoutes: 0,\n avgRoutingTimeMs: 0,\n accuracyRate: 0,\n };\n }\n\n /**\n * Register agent intent for routing\n *\n * @param intent - Agent intent configuration\n */\n async registerAgent(intent: AgentIntent): Promise<void> {\n this.agentIntents.set(intent.agentType, intent);\n\n // Generate embedding from description + examples\n const intentText = [\n intent.description,\n ...intent.examples,\n ...intent.tags,\n ].join(' ');\n\n const embedding = await this.embedder.embed(intentText);\n this.intentEmbeddings.set(intent.agentType, embedding);\n\n // Mark index as needing rebuild\n this.indexBuilt = false;\n }\n\n /**\n * Register multiple agents in batch\n *\n * @param intents - Array of agent intents\n */\n async registerAgents(intents: AgentIntent[]): Promise<void> {\n await Promise.all(intents.map(intent => this.registerAgent(intent)));\n }\n\n /**\n * Build HNSW index for fast routing\n *\n * In production, this would use @ruvector/router's native HNSW.\n * For this implementation, we use a simplified version.\n */\n buildIndex(): void {\n // In production: Initialize HNSW with intentEmbeddings\n // For now, we'll use brute-force search (still fast for 66 agents)\n this.indexBuilt = true;\n }\n\n /**\n * Route task to best agent using semantic similarity\n *\n * Process:\n * 1. Embed task description\n * 2. Search HNSW index for nearest intents\n * 3. Return top matches with confidence scores\n *\n * @param taskDescription - Natural language task description\n * @param k - Number of alternatives to return (default: 3)\n * @returns Routing result with primary agent and alternatives\n */\n async route(taskDescription: string, k: number = 3): Promise<RoutingResult> {\n const overallStartTime = performance.now();\n\n if (!this.indexBuilt) {\n this.buildIndex();\n }\n\n // Step 1: Embed task\n const embeddingStartTime = performance.now();\n const taskEmbedding = await this.embedder.embed(taskDescription);\n const embeddingTimeMs = performance.now() - embeddingStartTime;\n\n // Step 2: Search HNSW index\n const searchStartTime = performance.now();\n const candidates = this.searchHNSW(taskEmbedding, k + 1);\n const searchTimeMs = performance.now() - searchStartTime;\n\n if (candidates.length === 0) {\n throw new Error('No agents registered for routing');\n }\n\n // Step 3: Extract results\n const primaryAgent = candidates[0].agentType;\n const confidence = candidates[0].similarity;\n const alternatives = candidates.slice(1, k + 1).map(c => ({\n agentType: c.agentType,\n confidence: c.similarity,\n }));\n\n const matchedIntents = candidates\n .slice(0, k + 1)\n .map(c => this.agentIntents.get(c.agentType)?.description ?? '');\n\n const routingTimeMs = performance.now() - overallStartTime;\n\n // Update stats\n this.updateStats(routingTimeMs);\n\n return {\n primaryAgent,\n confidence,\n alternatives,\n matchedIntents,\n metrics: {\n routingTimeMs,\n embeddingTimeMs,\n searchTimeMs,\n candidatesEvaluated: this.agentIntents.size,\n },\n };\n }\n\n /**\n * Detect multiple intents in complex task\n *\n * Useful for tasks requiring coordination of multiple agents.\n *\n * @param taskDescription - Task that may require multiple agents\n * @param threshold - Minimum confidence for intent detection (default: 0.6)\n * @returns Multi-intent result with suggested execution order\n */\n async detectMultiIntent(\n taskDescription: string,\n threshold: number = 0.6\n ): Promise<MultiIntentResult> {\n // Split task into sentences or clauses\n const segments = this.segmentTask(taskDescription);\n\n // Route each segment\n const segmentResults = await Promise.all(\n segments.map(async segment => {\n const result = await this.route(segment.text, 1);\n return {\n ...result,\n matchedText: segment.text,\n };\n })\n );\n\n // Collect high-confidence intents\n const intents = segmentResults\n .filter(r => r.confidence >= threshold)\n .map(r => ({\n agentType: r.primaryAgent,\n confidence: r.confidence,\n matchedText: r.matchedText,\n }));\n\n // Deduplicate and order by confidence\n const uniqueIntents = this.deduplicateIntents(intents);\n const requiresMultiAgent = uniqueIntents.length > 1;\n\n // Suggest execution order based on dependencies\n const executionOrder = this.inferExecutionOrder(uniqueIntents, taskDescription);\n\n return {\n intents: uniqueIntents,\n requiresMultiAgent,\n executionOrder,\n };\n }\n\n /**\n * Get routing statistics\n *\n * @returns Cumulative routing metrics\n */\n getStats(): typeof this.routingStats {\n return { ...this.routingStats };\n }\n\n /**\n * Get all registered agents\n *\n * @returns Array of registered agent intents\n */\n getRegisteredAgents(): AgentIntent[] {\n return Array.from(this.agentIntents.values());\n }\n\n // ========================================================================\n // Private Helper Methods\n // ========================================================================\n\n /**\n * Search HNSW index for nearest neighbors\n *\n * In production, this would use @ruvector/router's native HNSW.\n * For this implementation, we use brute-force cosine similarity.\n *\n * @param queryEmbedding - Query vector\n * @param k - Number of results\n * @returns Top k candidates with similarity scores\n */\n private searchHNSW(queryEmbedding: Float32Array, k: number): Array<{\n agentType: string;\n similarity: number;\n }> {\n const candidates: Array<{ agentType: string; similarity: number }> = [];\n\n for (const [agentType, embedding] of Array.from(this.intentEmbeddings.entries())) {\n const similarity = this.cosineSimilarity(queryEmbedding, embedding);\n candidates.push({ agentType, similarity });\n }\n\n // Sort by similarity (descending)\n candidates.sort((a, b) => b.similarity - a.similarity);\n\n return candidates.slice(0, k);\n }\n\n /**\n * Calculate cosine similarity\n */\n private cosineSimilarity(a: Float32Array, b: Float32Array): number {\n if (a.length !== b.length) {\n throw new Error('Vectors must have same length');\n }\n\n let dotProduct = 0;\n let normA = 0;\n let normB = 0;\n\n for (let i = 0; i < a.length; i++) {\n dotProduct += a[i] * b[i];\n normA += a[i] * a[i];\n normB += b[i] * b[i];\n }\n\n const denom = Math.sqrt(normA) * Math.sqrt(normB);\n return denom === 0 ? 0 : dotProduct / denom;\n }\n\n /**\n * Segment task into independent clauses\n */\n private segmentTask(taskDescription: string): Array<{ text: string; index: number }> {\n // Split by sentences and coordination conjunctions\n const sentences = taskDescription.split(/[.!?]+/).filter(s => s.trim());\n\n const segments: Array<{ text: string; index: number }> = [];\n\n sentences.forEach((sentence, idx) => {\n // Further split by \"and\", \"then\", etc.\n const subSegments = sentence.split(/\\b(and|then|after|before)\\b/i);\n\n subSegments\n .filter((_, i) => i % 2 === 0) // Skip conjunctions\n .forEach(segment => {\n const trimmed = segment.trim();\n if (trimmed) {\n segments.push({ text: trimmed, index: idx });\n }\n });\n });\n\n return segments.length > 0 ? segments : [{ text: taskDescription, index: 0 }];\n }\n\n /**\n * Deduplicate intents by agent type\n */\n private deduplicateIntents(\n intents: Array<{ agentType: string; confidence: number; matchedText: string }>\n ): Array<{ agentType: string; confidence: number; matchedText: string }> {\n const seen = new Map<string, typeof intents[0]>();\n\n for (const intent of intents) {\n const existing = seen.get(intent.agentType);\n if (!existing || intent.confidence > existing.confidence) {\n seen.set(intent.agentType, intent);\n }\n }\n\n return Array.from(seen.values()).sort((a, b) => b.confidence - a.confidence);\n }\n\n /**\n * Infer execution order from intents and task description\n */\n private inferExecutionOrder(\n intents: Array<{ agentType: string; confidence: number; matchedText: string }>,\n taskDescription: string\n ): string[] {\n // Simple heuristic: order by position in original text\n const taskLower = taskDescription.toLowerCase();\n\n const withPositions = intents.map(intent => {\n const position = taskLower.indexOf(intent.matchedText.toLowerCase());\n return { ...intent, position };\n });\n\n withPositions.sort((a, b) => a.position - b.position);\n\n return withPositions.map(i => i.agentType);\n }\n\n /**\n * Update routing statistics\n */\n private updateStats(routingTimeMs: number): void {\n this.routingStats.totalRoutes++;\n\n const alpha = 0.1; // EMA smoothing\n this.routingStats.avgRoutingTimeMs =\n this.routingStats.avgRoutingTimeMs * (1 - alpha) + routingTimeMs * alpha;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"SemanticRouter.js","sourceRoot":"","sources":["../../src/routing/SemanticRouter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Semantic Router - HNSW-Powered Intent Matching\n *\n * Uses @ruvector/router's native HNSW index (VectorDb) when the package and\n * its platform binary are installed, and an exact brute-force cosine scan\n * otherwise. Both return the same ranking contract: similarity in [-1, 1],\n * highest first.\n *\n * Features:\n * - HNSW (Hierarchical Navigable Small World) index\n * - Intent classification for 66+ agents\n * - Sub-10ms routing latency\n * - Automatic intent embedding and indexing\n * - Multi-intent detection\n *\n * Performance:\n * - <10ms routing time\n * - >85% routing accuracy\n * - Support for 66+ agent types\n * - O(log N) search complexity\n */\n\n// Import from agentdb package\nimport type { EmbeddingService } from 'agentdb';\nimport { requireOptional } from '../integrations/optional.js';\n\n/** Structural subset of @ruvector/router's native VectorDb. */\ninterface NativeVectorDb {\n insert(id: string, vector: Float32Array): string;\n search(query: Float32Array, k: number): Array<{ id: string; score: number }>;\n}\ninterface RuvectorRouterModule {\n VectorDb: new (options: { dimensions: number; distanceMetric?: number }) => NativeVectorDb;\n DistanceMetric: { Cosine: number };\n}\n\nexport type SemanticIndexBackend = 'ruvector-router' | 'brute-force';\n\nexport interface AgentIntent {\n /** Agent type identifier */\n agentType: string;\n /** Natural language description of agent capabilities */\n description: string;\n /** Example tasks for this agent */\n examples: string[];\n /** Agent specialty tags */\n tags: string[];\n}\n\nexport interface RoutingResult {\n /** Primary agent selection */\n primaryAgent: string;\n /** Confidence score (0-1) */\n confidence: number;\n /** Secondary agent suggestions */\n alternatives: Array<{\n agentType: string;\n confidence: number;\n }>;\n /** Matched intent descriptions */\n matchedIntents: string[];\n /** Routing metrics */\n metrics: {\n routingTimeMs: number;\n embeddingTimeMs: number;\n searchTimeMs: number;\n candidatesEvaluated: number;\n };\n}\n\nexport interface MultiIntentResult {\n /** Detected intents in order of confidence */\n intents: Array<{\n agentType: string;\n confidence: number;\n matchedText: string;\n }>;\n /** Whether task requires multiple agents */\n requiresMultiAgent: boolean;\n /** Suggested execution order */\n executionOrder: string[];\n}\n\n/**\n * Semantic Router\n *\n * Provides intent-based agent routing:\n * 1. Register agent intents with descriptions\n * 2. Build HNSW index for fast semantic search\n * 3. Route tasks to agents based on intent similarity\n * 4. Support multi-intent detection for complex tasks\n */\nexport class SemanticRouter {\n private embedder: EmbeddingService;\n\n // Agent registry\n private agentIntents: Map<string, AgentIntent>;\n private intentEmbeddings: Map<string, Float32Array>;\n\n // Native HNSW index (@ruvector/router) or null for the brute-force scan\n private indexBuilt: boolean = false;\n private nativeIndex: NativeVectorDb | null = null;\n private backend: SemanticIndexBackend = 'brute-force';\n private readonly useNative: boolean;\n\n // Performance tracking\n private routingStats: {\n totalRoutes: number;\n avgRoutingTimeMs: number;\n accuracyRate: number; // Requires feedback\n };\n\n /**\n * @param embedder - Embedding service for intents and tasks\n * @param options.native - Use @ruvector/router when installed (default true)\n */\n constructor(embedder: EmbeddingService, options: { native?: boolean } = {}) {\n this.embedder = embedder;\n this.useNative = options.native ?? true;\n this.agentIntents = new Map();\n this.intentEmbeddings = new Map();\n this.routingStats = {\n totalRoutes: 0,\n avgRoutingTimeMs: 0,\n accuracyRate: 0,\n };\n }\n\n /**\n * Register agent intent for routing\n *\n * @param intent - Agent intent configuration\n */\n async registerAgent(intent: AgentIntent): Promise<void> {\n this.agentIntents.set(intent.agentType, intent);\n\n // Generate embedding from description + examples\n const intentText = [\n intent.description,\n ...intent.examples,\n ...intent.tags,\n ].join(' ');\n\n const embedding = await this.embedder.embed(intentText);\n this.intentEmbeddings.set(intent.agentType, embedding);\n\n // Mark index as needing rebuild\n this.indexBuilt = false;\n }\n\n /**\n * Register multiple agents in batch\n *\n * @param intents - Array of agent intents\n */\n async registerAgents(intents: AgentIntent[]): Promise<void> {\n await Promise.all(intents.map(intent => this.registerAgent(intent)));\n }\n\n /**\n * Build the routing index.\n *\n * Loads @ruvector/router's native HNSW (VectorDb, cosine metric) when it is\n * installed; otherwise routing uses an exact brute-force scan, which is\n * still fast at the ~66-agent scale.\n */\n buildIndex(): void {\n this.nativeIndex = null;\n this.backend = 'brute-force';\n const first = this.intentEmbeddings.values().next().value as Float32Array | undefined;\n const router = this.useNative && first\n ? requireOptional<RuvectorRouterModule>('@ruvector/router')\n : null;\n if (router && first) {\n try {\n const db = new router.VectorDb({\n dimensions: first.length,\n distanceMetric: router.DistanceMetric.Cosine,\n });\n for (const [agentType, embedding] of Array.from(this.intentEmbeddings.entries())) {\n db.insert(agentType, embedding instanceof Float32Array ? embedding : Float32Array.from(embedding));\n }\n this.nativeIndex = db;\n this.backend = 'ruvector-router';\n } catch {\n // Native binary missing for this platform, or a dimension mismatch:\n // keep the exact brute-force path.\n this.nativeIndex = null;\n }\n }\n this.indexBuilt = true;\n }\n\n /** Which index answered the last build: native HNSW or brute force. */\n getIndexBackend(): SemanticIndexBackend {\n return this.backend;\n }\n\n /**\n * Route task to best agent using semantic similarity\n *\n * Process:\n * 1. Embed task description\n * 2. Search HNSW index for nearest intents\n * 3. Return top matches with confidence scores\n *\n * @param taskDescription - Natural language task description\n * @param k - Number of alternatives to return (default: 3)\n * @returns Routing result with primary agent and alternatives\n */\n async route(taskDescription: string, k: number = 3): Promise<RoutingResult> {\n const overallStartTime = performance.now();\n\n if (!this.indexBuilt) {\n this.buildIndex();\n }\n\n // Step 1: Embed task\n const embeddingStartTime = performance.now();\n const taskEmbedding = await this.embedder.embed(taskDescription);\n const embeddingTimeMs = performance.now() - embeddingStartTime;\n\n // Step 2: Search HNSW index\n const searchStartTime = performance.now();\n const candidates = this.searchHNSW(taskEmbedding, k + 1);\n const searchTimeMs = performance.now() - searchStartTime;\n\n if (candidates.length === 0) {\n throw new Error('No agents registered for routing');\n }\n\n // Step 3: Extract results\n const primaryAgent = candidates[0].agentType;\n const confidence = candidates[0].similarity;\n const alternatives = candidates.slice(1, k + 1).map(c => ({\n agentType: c.agentType,\n confidence: c.similarity,\n }));\n\n const matchedIntents = candidates\n .slice(0, k + 1)\n .map(c => this.agentIntents.get(c.agentType)?.description ?? '');\n\n const routingTimeMs = performance.now() - overallStartTime;\n\n // Update stats\n this.updateStats(routingTimeMs);\n\n return {\n primaryAgent,\n confidence,\n alternatives,\n matchedIntents,\n metrics: {\n routingTimeMs,\n embeddingTimeMs,\n searchTimeMs,\n candidatesEvaluated: this.agentIntents.size,\n },\n };\n }\n\n /**\n * Detect multiple intents in complex task\n *\n * Useful for tasks requiring coordination of multiple agents.\n *\n * @param taskDescription - Task that may require multiple agents\n * @param threshold - Minimum confidence for intent detection (default: 0.6)\n * @returns Multi-intent result with suggested execution order\n */\n async detectMultiIntent(\n taskDescription: string,\n threshold: number = 0.6\n ): Promise<MultiIntentResult> {\n // Split task into sentences or clauses\n const segments = this.segmentTask(taskDescription);\n\n // Route each segment\n const segmentResults = await Promise.all(\n segments.map(async segment => {\n const result = await this.route(segment.text, 1);\n return {\n ...result,\n matchedText: segment.text,\n };\n })\n );\n\n // Collect high-confidence intents\n const intents = segmentResults\n .filter(r => r.confidence >= threshold)\n .map(r => ({\n agentType: r.primaryAgent,\n confidence: r.confidence,\n matchedText: r.matchedText,\n }));\n\n // Deduplicate and order by confidence\n const uniqueIntents = this.deduplicateIntents(intents);\n const requiresMultiAgent = uniqueIntents.length > 1;\n\n // Suggest execution order based on dependencies\n const executionOrder = this.inferExecutionOrder(uniqueIntents, taskDescription);\n\n return {\n intents: uniqueIntents,\n requiresMultiAgent,\n executionOrder,\n };\n }\n\n /**\n * Get routing statistics\n *\n * @returns Cumulative routing metrics\n */\n getStats(): typeof this.routingStats {\n return { ...this.routingStats };\n }\n\n /**\n * Get all registered agents\n *\n * @returns Array of registered agent intents\n */\n getRegisteredAgents(): AgentIntent[] {\n return Array.from(this.agentIntents.values());\n }\n\n // ========================================================================\n // Private Helper Methods\n // ========================================================================\n\n /**\n * Search the index for nearest neighbours.\n *\n * @ruvector/router reports cosine *distance* (0 = identical), so it is\n * converted to similarity (1 - distance) to keep \"higher is better\".\n *\n * @param queryEmbedding - Query vector\n * @param k - Number of results\n * @returns Top k candidates with similarity scores, highest first\n */\n private searchHNSW(queryEmbedding: Float32Array, k: number): Array<{\n agentType: string;\n similarity: number;\n }> {\n if (this.nativeIndex) {\n try {\n const query = queryEmbedding instanceof Float32Array ? queryEmbedding : Float32Array.from(queryEmbedding);\n return this.nativeIndex\n .search(query, Math.min(k, this.intentEmbeddings.size))\n .map((r) => ({ agentType: r.id, similarity: 1 - r.score }))\n .sort((a, b) => b.similarity - a.similarity);\n } catch {\n // fall through to the exact scan\n }\n }\n\n const candidates: Array<{ agentType: string; similarity: number }> = [];\n\n for (const [agentType, embedding] of Array.from(this.intentEmbeddings.entries())) {\n const similarity = this.cosineSimilarity(queryEmbedding, embedding);\n candidates.push({ agentType, similarity });\n }\n\n // Sort by similarity (descending)\n candidates.sort((a, b) => b.similarity - a.similarity);\n\n return candidates.slice(0, k);\n }\n\n /**\n * Calculate cosine similarity\n */\n private cosineSimilarity(a: Float32Array, b: Float32Array): number {\n if (a.length !== b.length) {\n throw new Error('Vectors must have same length');\n }\n\n let dotProduct = 0;\n let normA = 0;\n let normB = 0;\n\n for (let i = 0; i < a.length; i++) {\n dotProduct += a[i] * b[i];\n normA += a[i] * a[i];\n normB += b[i] * b[i];\n }\n\n const denom = Math.sqrt(normA) * Math.sqrt(normB);\n return denom === 0 ? 0 : dotProduct / denom;\n }\n\n /**\n * Segment task into independent clauses\n */\n private segmentTask(taskDescription: string): Array<{ text: string; index: number }> {\n // Split by sentences and coordination conjunctions\n const sentences = taskDescription.split(/[.!?]+/).filter(s => s.trim());\n\n const segments: Array<{ text: string; index: number }> = [];\n\n sentences.forEach((sentence, idx) => {\n // Further split by \"and\", \"then\", etc.\n const subSegments = sentence.split(/\\b(and|then|after|before)\\b/i);\n\n subSegments\n .filter((_, i) => i % 2 === 0) // Skip conjunctions\n .forEach(segment => {\n const trimmed = segment.trim();\n if (trimmed) {\n segments.push({ text: trimmed, index: idx });\n }\n });\n });\n\n return segments.length > 0 ? segments : [{ text: taskDescription, index: 0 }];\n }\n\n /**\n * Deduplicate intents by agent type\n */\n private deduplicateIntents(\n intents: Array<{ agentType: string; confidence: number; matchedText: string }>\n ): Array<{ agentType: string; confidence: number; matchedText: string }> {\n const seen = new Map<string, typeof intents[0]>();\n\n for (const intent of intents) {\n const existing = seen.get(intent.agentType);\n if (!existing || intent.confidence > existing.confidence) {\n seen.set(intent.agentType, intent);\n }\n }\n\n return Array.from(seen.values()).sort((a, b) => b.confidence - a.confidence);\n }\n\n /**\n * Infer execution order from intents and task description\n */\n private inferExecutionOrder(\n intents: Array<{ agentType: string; confidence: number; matchedText: string }>,\n taskDescription: string\n ): string[] {\n // Simple heuristic: order by position in original text\n const taskLower = taskDescription.toLowerCase();\n\n const withPositions = intents.map(intent => {\n const position = taskLower.indexOf(intent.matchedText.toLowerCase());\n return { ...intent, position };\n });\n\n withPositions.sort((a, b) => a.position - b.position);\n\n return withPositions.map(i => i.agentType);\n }\n\n /**\n * Update routing statistics\n */\n private updateStats(routingTimeMs: number): void {\n this.routingStats.totalRoutes++;\n\n const alpha = 0.1; // EMA smoothing\n this.routingStats.avgRoutingTimeMs =\n this.routingStats.avgRoutingTimeMs * (1 - alpha) + routingTimeMs * alpha;\n }\n}\n"]}
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
* Provides secure input validation for RuVector integration:
|
|
5
5
|
* - Task description validation
|
|
6
6
|
* - Configuration validation
|
|
7
|
-
* - Injection attack prevention
|
|
7
|
+
* - Injection attack prevention (prompt injection via aidefence when installed)
|
|
8
8
|
* - Resource exhaustion prevention
|
|
9
9
|
*/
|
|
10
|
+
import { type InjectionScan } from '../integrations/prompt-injection.js';
|
|
10
11
|
export interface ValidationOptions {
|
|
11
12
|
maxLength?: number;
|
|
12
13
|
minLength?: number;
|
|
@@ -17,16 +18,23 @@ export declare class ValidationError extends Error {
|
|
|
17
18
|
field?: string;
|
|
18
19
|
constructor(message: string, field?: string);
|
|
19
20
|
}
|
|
21
|
+
/** Thrown when task text is rejected by the prompt-injection policy. */
|
|
22
|
+
export declare class PromptInjectionError extends ValidationError {
|
|
23
|
+
scan: InjectionScan;
|
|
24
|
+
constructor(scan: InjectionScan, field?: string);
|
|
25
|
+
}
|
|
20
26
|
/**
|
|
21
27
|
* Input Validator
|
|
22
28
|
*
|
|
23
29
|
* Validates all external inputs to prevent:
|
|
24
|
-
* - Injection attacks (XSS, SQL injection, prompt injection
|
|
30
|
+
* - Injection attacks (XSS, SQL injection, and prompt injection — the latter
|
|
31
|
+
* through `scanPromptInjection`, see integrations/prompt-injection.ts)
|
|
25
32
|
* - Resource exhaustion (excessive length, recursion)
|
|
26
33
|
* - Malicious content (scripts, control characters)
|
|
27
34
|
*/
|
|
28
35
|
export declare class InputValidator {
|
|
29
36
|
private static readonly SUSPICIOUS_PATTERNS;
|
|
37
|
+
private static readonly warnedInjections;
|
|
30
38
|
private static readonly CONTROL_CHARS_REGEX;
|
|
31
39
|
/**
|
|
32
40
|
* Validate task description
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input-validator.d.ts","sourceRoot":"","sources":["../../src/utils/input-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,qBAAa,eAAgB,SAAQ,KAAK;IACJ,KAAK,CAAC,EAAE,MAAM;gBAAtC,OAAO,EAAE,MAAM,EAAS,KAAK,CAAC,EAAE,MAAM;CAInD;AAED
|
|
1
|
+
{"version":3,"file":"input-validator.d.ts","sourceRoot":"","sources":["../../src/utils/input-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAE9F,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,qBAAa,eAAgB,SAAQ,KAAK;IACJ,KAAK,CAAC,EAAE,MAAM;gBAAtC,OAAO,EAAE,MAAM,EAAS,KAAK,CAAC,EAAE,MAAM;CAInD;AAED,wEAAwE;AACxE,qBAAa,oBAAqB,SAAQ,eAAe;IACpC,IAAI,EAAE,aAAa;gBAAnB,IAAI,EAAE,aAAa,EAAE,KAAK,SAAoB;CASlE;AAED;;;;;;;;GAQG;AACH,qBAAa,cAAc;IAEzB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAUzC;IAEF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;IAG7D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAsB;IAEjE;;;;;;;OAOG;IACH,MAAM,CAAC,uBAAuB,CAC5B,eAAe,EAAE,MAAM,EACvB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,MAAM;IA6ET;;;;;;OAMG;IACH,MAAM,CAAC,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAuBnD;;;;;;OAMG;IACH,MAAM,CAAC,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAmBrD;;;;;;;;OAQG;IACH,MAAM,CAAC,eAAe,CACpB,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAY,EACjB,GAAG,GAAE,MAAe,GACnB,MAAM;IAuBT;;;;;;;;;OASG;IACH,MAAM,CAAC,mBAAmB,CACxB,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,EACjB,QAAQ,GAAE,MAAY,EACtB,SAAS,GAAE,MAAa,GACvB,MAAM,EAAE;IAoCX;;;;;;;OAOG;IACH,MAAM,CAAC,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACjD,MAAM,EAAE,OAAO,EACf,MAAM,EAAE;SACL,CAAC,IAAI,MAAM,CAAC,GAAG;YACd,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;YACjD,QAAQ,CAAC,EAAE,OAAO,CAAC;YACnB,GAAG,CAAC,EAAE,MAAM,CAAC;YACb,GAAG,CAAC,EAAE,MAAM,CAAC;YACb,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC;SACrC;KACF,GACA,CAAC;IAmEJ;;;;;OAKG;IACH,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAezC;;;;;;OAMG;IACH,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;CAiB5C;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAE/B,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG,mBAmB5C"}
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
* Provides secure input validation for RuVector integration:
|
|
5
5
|
* - Task description validation
|
|
6
6
|
* - Configuration validation
|
|
7
|
-
* - Injection attack prevention
|
|
7
|
+
* - Injection attack prevention (prompt injection via aidefence when installed)
|
|
8
8
|
* - Resource exhaustion prevention
|
|
9
9
|
*/
|
|
10
|
+
import { scanPromptInjection } from '../integrations/prompt-injection.js';
|
|
10
11
|
export class ValidationError extends Error {
|
|
11
12
|
field;
|
|
12
13
|
constructor(message, field) {
|
|
@@ -15,11 +16,23 @@ export class ValidationError extends Error {
|
|
|
15
16
|
this.name = 'ValidationError';
|
|
16
17
|
}
|
|
17
18
|
}
|
|
19
|
+
/** Thrown when task text is rejected by the prompt-injection policy. */
|
|
20
|
+
export class PromptInjectionError extends ValidationError {
|
|
21
|
+
scan;
|
|
22
|
+
constructor(scan, field = 'taskDescription') {
|
|
23
|
+
const top = scan.threats[0];
|
|
24
|
+
super(`Task description rejected: possible prompt injection (${scan.maxSeverity}` +
|
|
25
|
+
(top ? `, ${top.type}` : '') + `; engine ${scan.engine})`, field);
|
|
26
|
+
this.scan = scan;
|
|
27
|
+
this.name = 'PromptInjectionError';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
18
30
|
/**
|
|
19
31
|
* Input Validator
|
|
20
32
|
*
|
|
21
33
|
* Validates all external inputs to prevent:
|
|
22
|
-
* - Injection attacks (XSS, SQL injection, prompt injection
|
|
34
|
+
* - Injection attacks (XSS, SQL injection, and prompt injection — the latter
|
|
35
|
+
* through `scanPromptInjection`, see integrations/prompt-injection.ts)
|
|
23
36
|
* - Resource exhaustion (excessive length, recursion)
|
|
24
37
|
* - Malicious content (scripts, control characters)
|
|
25
38
|
*/
|
|
@@ -36,6 +49,7 @@ export class InputValidator {
|
|
|
36
49
|
/\.\.\//, // Path traversal
|
|
37
50
|
/[;\x00]/, // SQL injection chars
|
|
38
51
|
];
|
|
52
|
+
static warnedInjections = new Set();
|
|
39
53
|
// Control characters that should be removed
|
|
40
54
|
static CONTROL_CHARS_REGEX = /[\x00-\x1F\x7F]/g;
|
|
41
55
|
/**
|
|
@@ -83,6 +97,20 @@ export class InputValidator {
|
|
|
83
97
|
throw new ValidationError('Task description contains suspicious content', 'taskDescription');
|
|
84
98
|
}
|
|
85
99
|
}
|
|
100
|
+
// Prompt injection (aidefence when installed, built-in patterns otherwise)
|
|
101
|
+
const scan = scanPromptInjection(sanitized);
|
|
102
|
+
if (scan.decision === 'block') {
|
|
103
|
+
throw new PromptInjectionError(scan);
|
|
104
|
+
}
|
|
105
|
+
if (scan.decision === 'warn') {
|
|
106
|
+
const message = `possible prompt injection in task description (${scan.maxSeverity}: ` +
|
|
107
|
+
`${scan.threats.map((t) => t.type).join(', ')}; engine ${scan.engine})`;
|
|
108
|
+
// Once per distinct finding: an orchestrator loop would otherwise repeat it.
|
|
109
|
+
if (!InputValidator.warnedInjections.has(message)) {
|
|
110
|
+
InputValidator.warnedInjections.add(message);
|
|
111
|
+
process.emitWarning(message, { code: 'AGENTIC_FLOW_PROMPT_INJECTION' });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
86
114
|
}
|
|
87
115
|
return sanitized.trim();
|
|
88
116
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input-validator.js","sourceRoot":"","sources":["../../src/utils/input-validator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Input Validation Utilities\n *\n * Provides secure input validation for RuVector integration:\n * - Task description validation\n * - Configuration validation\n * - Injection attack prevention\n * - Resource exhaustion prevention\n */\n\nexport interface ValidationOptions {\n maxLength?: number;\n minLength?: number;\n allowEmpty?: boolean;\n sanitize?: boolean;\n}\n\nexport class ValidationError extends Error {\n constructor(message: string, public field?: string) {\n super(message);\n this.name = 'ValidationError';\n }\n}\n\n/**\n * Input Validator\n *\n * Validates all external inputs to prevent:\n * - Injection attacks (XSS, SQL injection, prompt injection)\n * - Resource exhaustion (excessive length, recursion)\n * - Malicious content (scripts, control characters)\n */\nexport class InputValidator {\n // Suspicious patterns that could indicate attacks\n private static readonly SUSPICIOUS_PATTERNS = [\n /<script/i, // XSS attempt\n /javascript:/i, // JavaScript protocol\n /data:text\\/html/i, // Data URI XSS\n /on\\w+\\s*=/i, // Event handlers\n /\\beval\\s*\\(/i, // eval() calls\n /\\bFunction\\s*\\(/i, // Function constructor\n /__proto__/, // Prototype pollution\n /\\.\\.\\//, // Path traversal\n /[;\\x00]/, // SQL injection chars\n ];\n\n // Control characters that should be removed\n private static readonly CONTROL_CHARS_REGEX = /[\\x00-\\x1F\\x7F]/g;\n\n /**\n * Validate task description\n *\n * @param taskDescription - User-provided task description\n * @param options - Validation options\n * @returns Sanitized task description\n * @throws ValidationError if invalid\n */\n static validateTaskDescription(\n taskDescription: string,\n options?: ValidationOptions\n ): string {\n const opts = {\n maxLength: options?.maxLength ?? 10000,\n minLength: options?.minLength ?? 1,\n allowEmpty: options?.allowEmpty ?? false,\n sanitize: options?.sanitize ?? true,\n };\n\n // Check for null/undefined\n if (taskDescription === null || taskDescription === undefined) {\n throw new ValidationError('Task description is required', 'taskDescription');\n }\n\n // Check type\n if (typeof taskDescription !== 'string') {\n throw new ValidationError(\n `Task description must be a string, got ${typeof taskDescription}`,\n 'taskDescription'\n );\n }\n\n // Check empty\n if (!opts.allowEmpty && taskDescription.trim().length === 0) {\n throw new ValidationError('Task description cannot be empty', 'taskDescription');\n }\n\n // Check length\n if (taskDescription.length < opts.minLength) {\n throw new ValidationError(\n `Task description too short (min ${opts.minLength} chars)`,\n 'taskDescription'\n );\n }\n\n if (taskDescription.length > opts.maxLength) {\n throw new ValidationError(\n `Task description too long (max ${opts.maxLength} chars)`,\n 'taskDescription'\n );\n }\n\n // Sanitize if requested\n let sanitized = taskDescription;\n if (opts.sanitize) {\n // Remove control characters\n sanitized = sanitized.replace(InputValidator.CONTROL_CHARS_REGEX, '');\n\n // Check for suspicious patterns\n for (const pattern of InputValidator.SUSPICIOUS_PATTERNS) {\n if (pattern.test(sanitized)) {\n throw new ValidationError(\n 'Task description contains suspicious content',\n 'taskDescription'\n );\n }\n }\n }\n\n return sanitized.trim();\n }\n\n /**\n * Validate agent name\n *\n * @param agentName - Agent identifier\n * @returns Sanitized agent name\n * @throws ValidationError if invalid\n */\n static validateAgentName(agentName: string): string {\n if (!agentName || typeof agentName !== 'string') {\n throw new ValidationError('Agent name is required', 'agentName');\n }\n\n if (agentName.length < 1 || agentName.length > 100) {\n throw new ValidationError(\n 'Agent name must be between 1-100 characters',\n 'agentName'\n );\n }\n\n // Only allow alphanumeric, dash, underscore\n if (!/^[a-zA-Z0-9_-]+$/.test(agentName)) {\n throw new ValidationError(\n 'Agent name can only contain letters, numbers, dash, and underscore',\n 'agentName'\n );\n }\n\n return agentName.toLowerCase();\n }\n\n /**\n * Validate confidence score\n *\n * @param confidence - Confidence score (0-1)\n * @returns Validated confidence\n * @throws ValidationError if invalid\n */\n static validateConfidence(confidence: number): number {\n if (typeof confidence !== 'number') {\n throw new ValidationError(\n `Confidence must be a number, got ${typeof confidence}`,\n 'confidence'\n );\n }\n\n if (Number.isNaN(confidence) || !Number.isFinite(confidence)) {\n throw new ValidationError('Confidence must be a valid number', 'confidence');\n }\n\n if (confidence < 0 || confidence > 1) {\n throw new ValidationError('Confidence must be between 0 and 1', 'confidence');\n }\n\n return confidence;\n }\n\n /**\n * Validate timeout value\n *\n * @param timeout - Timeout in milliseconds\n * @param min - Minimum allowed timeout (default: 100ms)\n * @param max - Maximum allowed timeout (default: 5 minutes)\n * @returns Validated timeout\n * @throws ValidationError if invalid\n */\n static validateTimeout(\n timeout: number,\n min: number = 100,\n max: number = 300000\n ): number {\n if (typeof timeout !== 'number') {\n throw new ValidationError(\n `Timeout must be a number, got ${typeof timeout}`,\n 'timeout'\n );\n }\n\n if (Number.isNaN(timeout) || !Number.isFinite(timeout)) {\n throw new ValidationError('Timeout must be a valid number', 'timeout');\n }\n\n if (timeout < min) {\n throw new ValidationError(`Timeout too short (min ${min}ms)`, 'timeout');\n }\n\n if (timeout > max) {\n throw new ValidationError(`Timeout too long (max ${max}ms)`, 'timeout');\n }\n\n return Math.floor(timeout);\n }\n\n /**\n * Validate array of strings\n *\n * @param array - Array to validate\n * @param fieldName - Field name for error messages\n * @param maxItems - Maximum number of items\n * @param maxLength - Maximum length per item\n * @returns Validated array\n * @throws ValidationError if invalid\n */\n static validateStringArray(\n array: unknown,\n fieldName: string,\n maxItems: number = 100,\n maxLength: number = 1000\n ): string[] {\n if (!Array.isArray(array)) {\n throw new ValidationError(`${fieldName} must be an array`, fieldName);\n }\n\n if (array.length > maxItems) {\n throw new ValidationError(\n `${fieldName} has too many items (max ${maxItems})`,\n fieldName\n );\n }\n\n const validated: string[] = [];\n for (let i = 0; i < array.length; i++) {\n const item = array[i];\n\n if (typeof item !== 'string') {\n throw new ValidationError(\n `${fieldName}[${i}] must be a string`,\n fieldName\n );\n }\n\n if (item.length > maxLength) {\n throw new ValidationError(\n `${fieldName}[${i}] too long (max ${maxLength} chars)`,\n fieldName\n );\n }\n\n validated.push(item);\n }\n\n return validated;\n }\n\n /**\n * Validate configuration object\n *\n * @param config - Configuration to validate\n * @param schema - Validation schema\n * @returns Validated configuration\n * @throws ValidationError if invalid\n */\n static validateConfig<T extends Record<string, any>>(\n config: unknown,\n schema: {\n [K in keyof T]: {\n type: 'string' | 'number' | 'boolean' | 'object';\n required?: boolean;\n min?: number;\n max?: number;\n validator?: (value: any) => boolean;\n };\n }\n ): T {\n if (!config || typeof config !== 'object') {\n throw new ValidationError('Configuration must be an object', 'config');\n }\n\n const validated: any = {};\n const configObj = config as Record<string, any>;\n\n for (const [key, rules] of Object.entries(schema)) {\n const value = configObj[key];\n\n // Check required\n if (rules.required && (value === undefined || value === null)) {\n throw new ValidationError(`Configuration field '${key}' is required`, key);\n }\n\n // Skip if optional and not provided\n if (!rules.required && (value === undefined || value === null)) {\n continue;\n }\n\n // Check type\n if (typeof value !== rules.type) {\n throw new ValidationError(\n `Configuration field '${key}' must be ${rules.type}, got ${typeof value}`,\n key\n );\n }\n\n // Validate numbers\n if (rules.type === 'number') {\n if (Number.isNaN(value) || !Number.isFinite(value)) {\n throw new ValidationError(\n `Configuration field '${key}' must be a valid number`,\n key\n );\n }\n\n if (rules.min !== undefined && value < rules.min) {\n throw new ValidationError(\n `Configuration field '${key}' must be >= ${rules.min}`,\n key\n );\n }\n\n if (rules.max !== undefined && value > rules.max) {\n throw new ValidationError(\n `Configuration field '${key}' must be <= ${rules.max}`,\n key\n );\n }\n }\n\n // Custom validator\n if (rules.validator && !rules.validator(value)) {\n throw new ValidationError(\n `Configuration field '${key}' failed validation`,\n key\n );\n }\n\n validated[key] = value;\n }\n\n return validated as T;\n }\n\n /**\n * Sanitize HTML to prevent XSS\n *\n * @param html - HTML string to sanitize\n * @returns Sanitized HTML (text only)\n */\n static sanitizeHtml(html: string): string {\n if (typeof html !== 'string') {\n return '';\n }\n\n // Strip all HTML tags, keep text only\n return html\n .replace(/<[^>]*>/g, '')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/&/g, '&')\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\");\n }\n\n /**\n * Validate email address\n *\n * @param email - Email to validate\n * @returns Normalized email\n * @throws ValidationError if invalid\n */\n static validateEmail(email: string): string {\n if (!email || typeof email !== 'string') {\n throw new ValidationError('Email is required', 'email');\n }\n\n // Basic email regex\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (!emailRegex.test(email)) {\n throw new ValidationError('Invalid email format', 'email');\n }\n\n if (email.length > 254) {\n throw new ValidationError('Email too long (max 254 chars)', 'email');\n }\n\n return email.toLowerCase().trim();\n }\n}\n\n/**\n * Validation middleware factory\n *\n * Creates validation middleware for Express/Fastify routes\n */\nexport function createValidationMiddleware(\n validator: (req: any) => void | Promise<void>\n) {\n return async (req: any, res: any, next: any) => {\n try {\n await validator(req);\n next();\n } catch (error) {\n if (error instanceof ValidationError) {\n res.status(400).json({\n error: 'Validation Error',\n message: error.message,\n field: error.field,\n });\n } else {\n res.status(500).json({\n error: 'Internal Server Error',\n message: 'Validation failed',\n });\n }\n }\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"input-validator.js","sourceRoot":"","sources":["../../src/utils/input-validator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Input Validation Utilities\n *\n * Provides secure input validation for RuVector integration:\n * - Task description validation\n * - Configuration validation\n * - Injection attack prevention (prompt injection via aidefence when installed)\n * - Resource exhaustion prevention\n */\n\nimport { scanPromptInjection, type InjectionScan } from '../integrations/prompt-injection.js';\n\nexport interface ValidationOptions {\n maxLength?: number;\n minLength?: number;\n allowEmpty?: boolean;\n sanitize?: boolean;\n}\n\nexport class ValidationError extends Error {\n constructor(message: string, public field?: string) {\n super(message);\n this.name = 'ValidationError';\n }\n}\n\n/** Thrown when task text is rejected by the prompt-injection policy. */\nexport class PromptInjectionError extends ValidationError {\n constructor(public scan: InjectionScan, field = 'taskDescription') {\n const top = scan.threats[0];\n super(\n `Task description rejected: possible prompt injection (${scan.maxSeverity}` +\n (top ? `, ${top.type}` : '') + `; engine ${scan.engine})`,\n field,\n );\n this.name = 'PromptInjectionError';\n }\n}\n\n/**\n * Input Validator\n *\n * Validates all external inputs to prevent:\n * - Injection attacks (XSS, SQL injection, and prompt injection — the latter\n * through `scanPromptInjection`, see integrations/prompt-injection.ts)\n * - Resource exhaustion (excessive length, recursion)\n * - Malicious content (scripts, control characters)\n */\nexport class InputValidator {\n // Suspicious patterns that could indicate attacks\n private static readonly SUSPICIOUS_PATTERNS = [\n /<script/i, // XSS attempt\n /javascript:/i, // JavaScript protocol\n /data:text\\/html/i, // Data URI XSS\n /on\\w+\\s*=/i, // Event handlers\n /\\beval\\s*\\(/i, // eval() calls\n /\\bFunction\\s*\\(/i, // Function constructor\n /__proto__/, // Prototype pollution\n /\\.\\.\\//, // Path traversal\n /[;\\x00]/, // SQL injection chars\n ];\n\n private static readonly warnedInjections = new Set<string>();\n\n // Control characters that should be removed\n private static readonly CONTROL_CHARS_REGEX = /[\\x00-\\x1F\\x7F]/g;\n\n /**\n * Validate task description\n *\n * @param taskDescription - User-provided task description\n * @param options - Validation options\n * @returns Sanitized task description\n * @throws ValidationError if invalid\n */\n static validateTaskDescription(\n taskDescription: string,\n options?: ValidationOptions\n ): string {\n const opts = {\n maxLength: options?.maxLength ?? 10000,\n minLength: options?.minLength ?? 1,\n allowEmpty: options?.allowEmpty ?? false,\n sanitize: options?.sanitize ?? true,\n };\n\n // Check for null/undefined\n if (taskDescription === null || taskDescription === undefined) {\n throw new ValidationError('Task description is required', 'taskDescription');\n }\n\n // Check type\n if (typeof taskDescription !== 'string') {\n throw new ValidationError(\n `Task description must be a string, got ${typeof taskDescription}`,\n 'taskDescription'\n );\n }\n\n // Check empty\n if (!opts.allowEmpty && taskDescription.trim().length === 0) {\n throw new ValidationError('Task description cannot be empty', 'taskDescription');\n }\n\n // Check length\n if (taskDescription.length < opts.minLength) {\n throw new ValidationError(\n `Task description too short (min ${opts.minLength} chars)`,\n 'taskDescription'\n );\n }\n\n if (taskDescription.length > opts.maxLength) {\n throw new ValidationError(\n `Task description too long (max ${opts.maxLength} chars)`,\n 'taskDescription'\n );\n }\n\n // Sanitize if requested\n let sanitized = taskDescription;\n if (opts.sanitize) {\n // Remove control characters\n sanitized = sanitized.replace(InputValidator.CONTROL_CHARS_REGEX, '');\n\n // Check for suspicious patterns\n for (const pattern of InputValidator.SUSPICIOUS_PATTERNS) {\n if (pattern.test(sanitized)) {\n throw new ValidationError(\n 'Task description contains suspicious content',\n 'taskDescription'\n );\n }\n }\n\n // Prompt injection (aidefence when installed, built-in patterns otherwise)\n const scan = scanPromptInjection(sanitized);\n if (scan.decision === 'block') {\n throw new PromptInjectionError(scan);\n }\n if (scan.decision === 'warn') {\n const message =\n `possible prompt injection in task description (${scan.maxSeverity}: ` +\n `${scan.threats.map((t) => t.type).join(', ')}; engine ${scan.engine})`;\n // Once per distinct finding: an orchestrator loop would otherwise repeat it.\n if (!InputValidator.warnedInjections.has(message)) {\n InputValidator.warnedInjections.add(message);\n process.emitWarning(message, { code: 'AGENTIC_FLOW_PROMPT_INJECTION' });\n }\n }\n }\n\n return sanitized.trim();\n }\n\n /**\n * Validate agent name\n *\n * @param agentName - Agent identifier\n * @returns Sanitized agent name\n * @throws ValidationError if invalid\n */\n static validateAgentName(agentName: string): string {\n if (!agentName || typeof agentName !== 'string') {\n throw new ValidationError('Agent name is required', 'agentName');\n }\n\n if (agentName.length < 1 || agentName.length > 100) {\n throw new ValidationError(\n 'Agent name must be between 1-100 characters',\n 'agentName'\n );\n }\n\n // Only allow alphanumeric, dash, underscore\n if (!/^[a-zA-Z0-9_-]+$/.test(agentName)) {\n throw new ValidationError(\n 'Agent name can only contain letters, numbers, dash, and underscore',\n 'agentName'\n );\n }\n\n return agentName.toLowerCase();\n }\n\n /**\n * Validate confidence score\n *\n * @param confidence - Confidence score (0-1)\n * @returns Validated confidence\n * @throws ValidationError if invalid\n */\n static validateConfidence(confidence: number): number {\n if (typeof confidence !== 'number') {\n throw new ValidationError(\n `Confidence must be a number, got ${typeof confidence}`,\n 'confidence'\n );\n }\n\n if (Number.isNaN(confidence) || !Number.isFinite(confidence)) {\n throw new ValidationError('Confidence must be a valid number', 'confidence');\n }\n\n if (confidence < 0 || confidence > 1) {\n throw new ValidationError('Confidence must be between 0 and 1', 'confidence');\n }\n\n return confidence;\n }\n\n /**\n * Validate timeout value\n *\n * @param timeout - Timeout in milliseconds\n * @param min - Minimum allowed timeout (default: 100ms)\n * @param max - Maximum allowed timeout (default: 5 minutes)\n * @returns Validated timeout\n * @throws ValidationError if invalid\n */\n static validateTimeout(\n timeout: number,\n min: number = 100,\n max: number = 300000\n ): number {\n if (typeof timeout !== 'number') {\n throw new ValidationError(\n `Timeout must be a number, got ${typeof timeout}`,\n 'timeout'\n );\n }\n\n if (Number.isNaN(timeout) || !Number.isFinite(timeout)) {\n throw new ValidationError('Timeout must be a valid number', 'timeout');\n }\n\n if (timeout < min) {\n throw new ValidationError(`Timeout too short (min ${min}ms)`, 'timeout');\n }\n\n if (timeout > max) {\n throw new ValidationError(`Timeout too long (max ${max}ms)`, 'timeout');\n }\n\n return Math.floor(timeout);\n }\n\n /**\n * Validate array of strings\n *\n * @param array - Array to validate\n * @param fieldName - Field name for error messages\n * @param maxItems - Maximum number of items\n * @param maxLength - Maximum length per item\n * @returns Validated array\n * @throws ValidationError if invalid\n */\n static validateStringArray(\n array: unknown,\n fieldName: string,\n maxItems: number = 100,\n maxLength: number = 1000\n ): string[] {\n if (!Array.isArray(array)) {\n throw new ValidationError(`${fieldName} must be an array`, fieldName);\n }\n\n if (array.length > maxItems) {\n throw new ValidationError(\n `${fieldName} has too many items (max ${maxItems})`,\n fieldName\n );\n }\n\n const validated: string[] = [];\n for (let i = 0; i < array.length; i++) {\n const item = array[i];\n\n if (typeof item !== 'string') {\n throw new ValidationError(\n `${fieldName}[${i}] must be a string`,\n fieldName\n );\n }\n\n if (item.length > maxLength) {\n throw new ValidationError(\n `${fieldName}[${i}] too long (max ${maxLength} chars)`,\n fieldName\n );\n }\n\n validated.push(item);\n }\n\n return validated;\n }\n\n /**\n * Validate configuration object\n *\n * @param config - Configuration to validate\n * @param schema - Validation schema\n * @returns Validated configuration\n * @throws ValidationError if invalid\n */\n static validateConfig<T extends Record<string, any>>(\n config: unknown,\n schema: {\n [K in keyof T]: {\n type: 'string' | 'number' | 'boolean' | 'object';\n required?: boolean;\n min?: number;\n max?: number;\n validator?: (value: any) => boolean;\n };\n }\n ): T {\n if (!config || typeof config !== 'object') {\n throw new ValidationError('Configuration must be an object', 'config');\n }\n\n const validated: any = {};\n const configObj = config as Record<string, any>;\n\n for (const [key, rules] of Object.entries(schema)) {\n const value = configObj[key];\n\n // Check required\n if (rules.required && (value === undefined || value === null)) {\n throw new ValidationError(`Configuration field '${key}' is required`, key);\n }\n\n // Skip if optional and not provided\n if (!rules.required && (value === undefined || value === null)) {\n continue;\n }\n\n // Check type\n if (typeof value !== rules.type) {\n throw new ValidationError(\n `Configuration field '${key}' must be ${rules.type}, got ${typeof value}`,\n key\n );\n }\n\n // Validate numbers\n if (rules.type === 'number') {\n if (Number.isNaN(value) || !Number.isFinite(value)) {\n throw new ValidationError(\n `Configuration field '${key}' must be a valid number`,\n key\n );\n }\n\n if (rules.min !== undefined && value < rules.min) {\n throw new ValidationError(\n `Configuration field '${key}' must be >= ${rules.min}`,\n key\n );\n }\n\n if (rules.max !== undefined && value > rules.max) {\n throw new ValidationError(\n `Configuration field '${key}' must be <= ${rules.max}`,\n key\n );\n }\n }\n\n // Custom validator\n if (rules.validator && !rules.validator(value)) {\n throw new ValidationError(\n `Configuration field '${key}' failed validation`,\n key\n );\n }\n\n validated[key] = value;\n }\n\n return validated as T;\n }\n\n /**\n * Sanitize HTML to prevent XSS\n *\n * @param html - HTML string to sanitize\n * @returns Sanitized HTML (text only)\n */\n static sanitizeHtml(html: string): string {\n if (typeof html !== 'string') {\n return '';\n }\n\n // Strip all HTML tags, keep text only\n return html\n .replace(/<[^>]*>/g, '')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/&/g, '&')\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\");\n }\n\n /**\n * Validate email address\n *\n * @param email - Email to validate\n * @returns Normalized email\n * @throws ValidationError if invalid\n */\n static validateEmail(email: string): string {\n if (!email || typeof email !== 'string') {\n throw new ValidationError('Email is required', 'email');\n }\n\n // Basic email regex\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (!emailRegex.test(email)) {\n throw new ValidationError('Invalid email format', 'email');\n }\n\n if (email.length > 254) {\n throw new ValidationError('Email too long (max 254 chars)', 'email');\n }\n\n return email.toLowerCase().trim();\n }\n}\n\n/**\n * Validation middleware factory\n *\n * Creates validation middleware for Express/Fastify routes\n */\nexport function createValidationMiddleware(\n validator: (req: any) => void | Promise<void>\n) {\n return async (req: any, res: any, next: any) => {\n try {\n await validator(req);\n next();\n } catch (error) {\n if (error instanceof ValidationError) {\n res.status(400).json({\n error: 'Validation Error',\n message: error.message,\n field: error.field,\n });\n } else {\n res.status(500).json({\n error: 'Internal Server Error',\n message: 'Validation failed',\n });\n }\n }\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-cache.d.ts","sourceRoot":"","sources":["../../src/utils/model-cache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,UAAU,UAAU;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,cAAM,UAAU;IACd,OAAO,CAAC,KAAK,CAAkC;IAC/C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,WAAW,CAAK;gBAEZ,SAAS,GAAE,MAAY;IAInC;;OAEG;IACG,SAAS,CAAC,CAAC,EACf,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACxB,YAAY,GAAE,MAAyB,GACtC,OAAO,CAAC,CAAC,CAAC;IA4Bb;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAUlC;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,YAAY,GAAE,MAAyB,GAAG,IAAI;IAW3E;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI5B;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,QAAQ,IAAI,UAAU;IAoBtB;;OAEG;IACH,OAAO,CAAC,aAAa;CAuBtB;AAGD,eAAO,MAAM,UAAU,YAAmB,CAAC;AAG3C,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"model-cache.d.ts","sourceRoot":"","sources":["../../src/utils/model-cache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,UAAU,UAAU;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,cAAM,UAAU;IACd,OAAO,CAAC,KAAK,CAAkC;IAC/C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,WAAW,CAAK;gBAEZ,SAAS,GAAE,MAAY;IAInC;;OAEG;IACG,SAAS,CAAC,CAAC,EACf,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACxB,YAAY,GAAE,MAAyB,GACtC,OAAO,CAAC,CAAC,CAAC;IA4Bb;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAUlC;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,YAAY,GAAE,MAAyB,GAAG,IAAI;IAW3E;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI5B;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,QAAQ,IAAI,UAAU;IAoBtB;;OAEG;IACH,OAAO,CAAC,aAAa;CAuBtB;AAGD,eAAO,MAAM,UAAU,YAAmB,CAAC;AAG3C,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,GAAG,CAAC,CAa1D;AAED,wBAAsB,6BAA6B,CACjD,IAAI,GAAE,MAA6B,EACnC,KAAK,GAAE,MAAkC,GACxC,OAAO,CAAC,GAAG,CAAC,CASd;AAED,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,GAAG,CAAC,CAS1D"}
|
|
@@ -132,31 +132,12 @@ export const modelCache = new ModelCache();
|
|
|
132
132
|
// Convenience functions
|
|
133
133
|
export async function getCachedOnnxEmbedder() {
|
|
134
134
|
return modelCache.getOrLoad('onnx-embeddings', async () => {
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
//
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
data.message?.includes('Import')) {
|
|
142
|
-
return false;
|
|
143
|
-
}
|
|
144
|
-
// @ts-ignore
|
|
145
|
-
return originalEmit.apply(process, [name, data, ...args]);
|
|
146
|
-
};
|
|
147
|
-
try {
|
|
148
|
-
const onnxModule = await import('ruvector-onnx-embeddings-wasm');
|
|
149
|
-
const EmbedderClass = onnxModule.OnnxEmbeddings || onnxModule.default;
|
|
150
|
-
if (EmbedderClass) {
|
|
151
|
-
const embedder = new EmbedderClass();
|
|
152
|
-
await embedder.initialize?.();
|
|
153
|
-
return embedder;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
finally {
|
|
157
|
-
process.emit = originalEmit;
|
|
158
|
-
}
|
|
159
|
-
return null;
|
|
135
|
+
// ruvector-onnx-embeddings-wasm exposes WasmEmbedder (not the
|
|
136
|
+
// OnnxEmbeddings class this used to look for) and cannot be import()ed
|
|
137
|
+
// as published; the shared loader handles both. Resolves to an object
|
|
138
|
+
// with async embed(text) -> Float32Array, or null.
|
|
139
|
+
const { getOnnxWasmEmbedder } = await import('../integrations/onnx-wasm-embedder.js');
|
|
140
|
+
return getOnnxWasmEmbedder();
|
|
160
141
|
}, 100 * 1024 * 1024 // 100MB estimate for ONNX model
|
|
161
142
|
);
|
|
162
143
|
}
|