vesper-memory 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/.env.example +28 -0
  2. package/CHANGELOG.md +137 -0
  3. package/LICENSE +21 -0
  4. package/README.md +665 -0
  5. package/config/sqlite-schema.sql +413 -0
  6. package/dist/benchmark/index.d.ts +18 -0
  7. package/dist/benchmark/index.d.ts.map +1 -0
  8. package/dist/benchmark/index.js +19 -0
  9. package/dist/benchmark/index.js.map +1 -0
  10. package/dist/benchmark/metrics-collector.d.ts +90 -0
  11. package/dist/benchmark/metrics-collector.d.ts.map +1 -0
  12. package/dist/benchmark/metrics-collector.js +196 -0
  13. package/dist/benchmark/metrics-collector.js.map +1 -0
  14. package/dist/benchmark/report-generator.d.ts +35 -0
  15. package/dist/benchmark/report-generator.d.ts.map +1 -0
  16. package/dist/benchmark/report-generator.js +221 -0
  17. package/dist/benchmark/report-generator.js.map +1 -0
  18. package/dist/benchmark/runner.d.ts +30 -0
  19. package/dist/benchmark/runner.d.ts.map +1 -0
  20. package/dist/benchmark/runner.js +308 -0
  21. package/dist/benchmark/runner.js.map +1 -0
  22. package/dist/benchmark/scenarios/context-recall.d.ts +65 -0
  23. package/dist/benchmark/scenarios/context-recall.d.ts.map +1 -0
  24. package/dist/benchmark/scenarios/context-recall.js +180 -0
  25. package/dist/benchmark/scenarios/context-recall.js.map +1 -0
  26. package/dist/benchmark/scenarios/index.d.ts +34 -0
  27. package/dist/benchmark/scenarios/index.d.ts.map +1 -0
  28. package/dist/benchmark/scenarios/index.js +230 -0
  29. package/dist/benchmark/scenarios/index.js.map +1 -0
  30. package/dist/benchmark/statistics.d.ts +125 -0
  31. package/dist/benchmark/statistics.d.ts.map +1 -0
  32. package/dist/benchmark/statistics.js +520 -0
  33. package/dist/benchmark/statistics.js.map +1 -0
  34. package/dist/benchmark/types.d.ts +458 -0
  35. package/dist/benchmark/types.d.ts.map +1 -0
  36. package/dist/benchmark/types.js +297 -0
  37. package/dist/benchmark/types.js.map +1 -0
  38. package/dist/cli 2.js +583 -0
  39. package/dist/cli.d 2.ts +8 -0
  40. package/dist/cli.d.ts +8 -0
  41. package/dist/cli.d.ts 2.map +1 -0
  42. package/dist/cli.d.ts.map +1 -0
  43. package/dist/cli.js +583 -0
  44. package/dist/cli.js 2.map +1 -0
  45. package/dist/cli.js.map +1 -0
  46. package/dist/config/rate-limits.d.ts +76 -0
  47. package/dist/config/rate-limits.d.ts.map +1 -0
  48. package/dist/config/rate-limits.js +161 -0
  49. package/dist/config/rate-limits.js.map +1 -0
  50. package/dist/config 2/rate-limits.d.ts +76 -0
  51. package/dist/config 2/rate-limits.d.ts.map +1 -0
  52. package/dist/config 2/rate-limits.js +161 -0
  53. package/dist/config 2/rate-limits.js.map +1 -0
  54. package/dist/consolidation/pipeline.d.ts +52 -0
  55. package/dist/consolidation/pipeline.d.ts.map +1 -0
  56. package/dist/consolidation/pipeline.js +193 -0
  57. package/dist/consolidation/pipeline.js.map +1 -0
  58. package/dist/consolidation 2/pipeline.d.ts +52 -0
  59. package/dist/consolidation 2/pipeline.d.ts.map +1 -0
  60. package/dist/consolidation 2/pipeline.js +193 -0
  61. package/dist/consolidation 2/pipeline.js.map +1 -0
  62. package/dist/embeddings/client.d.ts +95 -0
  63. package/dist/embeddings/client.d.ts.map +1 -0
  64. package/dist/embeddings/client.js +162 -0
  65. package/dist/embeddings/client.js.map +1 -0
  66. package/dist/embeddings 2/client.d.ts +94 -0
  67. package/dist/embeddings 2/client.d.ts.map +1 -0
  68. package/dist/embeddings 2/client.js +144 -0
  69. package/dist/embeddings 2/client.js.map +1 -0
  70. package/dist/memory-layers/semantic-memory.d.ts +76 -0
  71. package/dist/memory-layers/semantic-memory.d.ts.map +1 -0
  72. package/dist/memory-layers/semantic-memory.js +231 -0
  73. package/dist/memory-layers/semantic-memory.js.map +1 -0
  74. package/dist/memory-layers/skill-library.d.ts +25 -0
  75. package/dist/memory-layers/skill-library.d.ts.map +1 -0
  76. package/dist/memory-layers/skill-library.js +54 -0
  77. package/dist/memory-layers/skill-library.js.map +1 -0
  78. package/dist/memory-layers/working-memory.d.ts +57 -0
  79. package/dist/memory-layers/working-memory.d.ts.map +1 -0
  80. package/dist/memory-layers/working-memory.js +153 -0
  81. package/dist/memory-layers/working-memory.js.map +1 -0
  82. package/dist/memory-layers 2/semantic-memory.d.ts +33 -0
  83. package/dist/memory-layers 2/semantic-memory.d.ts.map +1 -0
  84. package/dist/memory-layers 2/semantic-memory.js +114 -0
  85. package/dist/memory-layers 2/semantic-memory.js.map +1 -0
  86. package/dist/memory-layers 2/skill-library.d.ts +25 -0
  87. package/dist/memory-layers 2/skill-library.d.ts.map +1 -0
  88. package/dist/memory-layers 2/skill-library.js +54 -0
  89. package/dist/memory-layers 2/skill-library.js.map +1 -0
  90. package/dist/memory-layers 2/working-memory.d.ts +57 -0
  91. package/dist/memory-layers 2/working-memory.d.ts.map +1 -0
  92. package/dist/memory-layers 2/working-memory.js +153 -0
  93. package/dist/memory-layers 2/working-memory.js.map +1 -0
  94. package/dist/middleware/auth.d.ts +287 -0
  95. package/dist/middleware/auth.d.ts.map +1 -0
  96. package/dist/middleware/auth.js +610 -0
  97. package/dist/middleware/auth.js.map +1 -0
  98. package/dist/middleware 2/auth.d.ts +287 -0
  99. package/dist/middleware 2/auth.d.ts.map +1 -0
  100. package/dist/middleware 2/auth.js +610 -0
  101. package/dist/middleware 2/auth.js.map +1 -0
  102. package/dist/monitoring/health.d.ts +241 -0
  103. package/dist/monitoring/health.d.ts.map +1 -0
  104. package/dist/monitoring/health.js +649 -0
  105. package/dist/monitoring/health.js.map +1 -0
  106. package/dist/monitoring/metrics.d.ts +153 -0
  107. package/dist/monitoring/metrics.d.ts.map +1 -0
  108. package/dist/monitoring/metrics.js +349 -0
  109. package/dist/monitoring/metrics.js.map +1 -0
  110. package/dist/monitoring 2/health.d.ts +241 -0
  111. package/dist/monitoring 2/health.d.ts.map +1 -0
  112. package/dist/monitoring 2/health.js +649 -0
  113. package/dist/monitoring 2/health.js.map +1 -0
  114. package/dist/monitoring 2/metrics.d.ts +153 -0
  115. package/dist/monitoring 2/metrics.d.ts.map +1 -0
  116. package/dist/monitoring 2/metrics.js +349 -0
  117. package/dist/monitoring 2/metrics.js.map +1 -0
  118. package/dist/retrieval/hybrid-search.d.ts +186 -0
  119. package/dist/retrieval/hybrid-search.d.ts.map +1 -0
  120. package/dist/retrieval/hybrid-search.js +330 -0
  121. package/dist/retrieval/hybrid-search.js.map +1 -0
  122. package/dist/retrieval 2/hybrid-search.d.ts +186 -0
  123. package/dist/retrieval 2/hybrid-search.d.ts.map +1 -0
  124. package/dist/retrieval 2/hybrid-search.js +327 -0
  125. package/dist/retrieval 2/hybrid-search.js.map +1 -0
  126. package/dist/router/smart-router.d.ts +157 -0
  127. package/dist/router/smart-router.d.ts.map +1 -0
  128. package/dist/router/smart-router.js +524 -0
  129. package/dist/router/smart-router.js.map +1 -0
  130. package/dist/router 2/smart-router.d.ts +111 -0
  131. package/dist/router 2/smart-router.d.ts.map +1 -0
  132. package/dist/router 2/smart-router.js +383 -0
  133. package/dist/router 2/smart-router.js.map +1 -0
  134. package/dist/security/rate-limit-middleware.d.ts +119 -0
  135. package/dist/security/rate-limit-middleware.d.ts.map +1 -0
  136. package/dist/security/rate-limit-middleware.js +193 -0
  137. package/dist/security/rate-limit-middleware.js.map +1 -0
  138. package/dist/security 2/rate-limit-middleware.d.ts +119 -0
  139. package/dist/security 2/rate-limit-middleware.d.ts.map +1 -0
  140. package/dist/security 2/rate-limit-middleware.js +193 -0
  141. package/dist/security 2/rate-limit-middleware.js.map +1 -0
  142. package/dist/server 2.js +861 -0
  143. package/dist/server-wrapper 2.js +170 -0
  144. package/dist/server-wrapper.d 2.ts +12 -0
  145. package/dist/server-wrapper.d.ts +12 -0
  146. package/dist/server-wrapper.d.ts 2.map +1 -0
  147. package/dist/server-wrapper.d.ts.map +1 -0
  148. package/dist/server-wrapper.js +170 -0
  149. package/dist/server-wrapper.js 2.map +1 -0
  150. package/dist/server-wrapper.js.map +1 -0
  151. package/dist/server.d 2.ts +14 -0
  152. package/dist/server.d.ts +14 -0
  153. package/dist/server.d.ts 2.map +1 -0
  154. package/dist/server.d.ts.map +1 -0
  155. package/dist/server.js +656 -0
  156. package/dist/server.js 2.map +1 -0
  157. package/dist/server.js.map +1 -0
  158. package/dist/synthesis/conflict-detector.d.ts +43 -0
  159. package/dist/synthesis/conflict-detector.d.ts.map +1 -0
  160. package/dist/synthesis/conflict-detector.js +125 -0
  161. package/dist/synthesis/conflict-detector.js.map +1 -0
  162. package/dist/synthesis 2/conflict-detector.d.ts +43 -0
  163. package/dist/synthesis 2/conflict-detector.d.ts.map +1 -0
  164. package/dist/synthesis 2/conflict-detector.js +125 -0
  165. package/dist/synthesis 2/conflict-detector.js.map +1 -0
  166. package/dist/utils/monitoring.d.ts +25 -0
  167. package/dist/utils/monitoring.d.ts.map +1 -0
  168. package/dist/utils/monitoring.js +41 -0
  169. package/dist/utils/monitoring.js.map +1 -0
  170. package/dist/utils/rate-limiter.d.ts +97 -0
  171. package/dist/utils/rate-limiter.d.ts.map +1 -0
  172. package/dist/utils/rate-limiter.js +166 -0
  173. package/dist/utils/rate-limiter.js.map +1 -0
  174. package/dist/utils/validation.d.ts +139 -0
  175. package/dist/utils/validation.d.ts.map +1 -0
  176. package/dist/utils/validation.js +195 -0
  177. package/dist/utils/validation.js.map +1 -0
  178. package/dist/utils 2/monitoring.d.ts +25 -0
  179. package/dist/utils 2/monitoring.d.ts.map +1 -0
  180. package/dist/utils 2/monitoring.js +41 -0
  181. package/dist/utils 2/monitoring.js.map +1 -0
  182. package/dist/utils 2/rate-limiter.d.ts +97 -0
  183. package/dist/utils 2/rate-limiter.d.ts.map +1 -0
  184. package/dist/utils 2/rate-limiter.js +166 -0
  185. package/dist/utils 2/rate-limiter.js.map +1 -0
  186. package/dist/utils 2/validation.d.ts +139 -0
  187. package/dist/utils 2/validation.d.ts.map +1 -0
  188. package/dist/utils 2/validation.js +195 -0
  189. package/dist/utils 2/validation.js.map +1 -0
  190. package/docker-compose.yml +65 -0
  191. package/embedding-service/Dockerfile +29 -0
  192. package/embedding-service/README.md +68 -0
  193. package/embedding-service/requirements.txt +6 -0
  194. package/embedding-service/server.py +110 -0
  195. package/package.json +92 -0
  196. package/scripts/FRESH_INSTALL.md +280 -0
  197. package/scripts/README.md +101 -0
  198. package/scripts/ensure-infrastructure.sh +38 -0
  199. package/scripts/fresh-install-auto.sh +96 -0
  200. package/scripts/fresh-install.sh +167 -0
  201. package/scripts/health-check.sh +72 -0
  202. package/scripts/init-qdrant.ts +201 -0
  203. package/scripts/postinstall.js +94 -0
  204. package/scripts/run-accuracy-benchmark.ts +1237 -0
  205. package/scripts/run-real-benchmark.ts +581 -0
  206. package/scripts/test-mcp-server.sh +38 -0
@@ -0,0 +1,383 @@
1
+ /**
2
+ * Smart Query Router
3
+ *
4
+ * Implements intelligent routing logic from v3.0 plan:
5
+ * 1. Always check working memory first (fast path)
6
+ * 2. Classify query type using regex patterns
7
+ * 3. Route to appropriate handler based on classification
8
+ * 4. Fall back to hybrid search for complex queries
9
+ */
10
+ /**
11
+ * Query type enumeration
12
+ * Used to classify queries and route to appropriate handlers
13
+ */
14
+ export var QueryType;
15
+ (function (QueryType) {
16
+ QueryType["FACTUAL"] = "factual";
17
+ QueryType["PREFERENCE"] = "preference";
18
+ QueryType["PROJECT"] = "project";
19
+ QueryType["TEMPORAL"] = "temporal";
20
+ QueryType["SKILL"] = "skill";
21
+ QueryType["COMPLEX"] = "complex";
22
+ })(QueryType || (QueryType = {}));
23
+ /**
24
+ * Classify a query into one of the six query types
25
+ *
26
+ * Uses simple regex patterns to identify query intent without LLM calls.
27
+ * Falls back to 'complex' for ambiguous queries.
28
+ *
29
+ * Patterns (in order of specificity):
30
+ * - skill: "like before", "same as", "same way", "how you", "analyze"
31
+ * - factual: "what is", "who is", "where is"
32
+ * - temporal: "last week", "yesterday", "recently", etc.
33
+ * - preference: "prefer", "want", "style", "favorite"
34
+ * - project: "project", "working on", "decided", "building", "creating", "developing"
35
+ * - complex: fallback for anything else
36
+ */
37
+ export function classifyQuery(query) {
38
+ const normalizedQuery = query.toLowerCase().trim();
39
+ // Pattern definitions with confidence scores
40
+ // NOTE: More specific patterns should be checked first to avoid ambiguity
41
+ const patterns = [
42
+ // Skill patterns are most specific - check before preference and temporal
43
+ {
44
+ type: QueryType.SKILL,
45
+ regex: /\b(like before|same as|same way|how you)\b/i,
46
+ confidence: 0.85,
47
+ label: "skill"
48
+ },
49
+ {
50
+ type: QueryType.SKILL,
51
+ regex: /\banalyze\b/i,
52
+ confidence: 0.75,
53
+ label: "skill_analyze"
54
+ },
55
+ // Temporal patterns - check before factual WH questions since temporal is more specific
56
+ {
57
+ type: QueryType.TEMPORAL,
58
+ regex: /\b(last week|last month|last year|last time)\b/i,
59
+ confidence: 0.95,
60
+ label: "temporal_specific"
61
+ },
62
+ {
63
+ type: QueryType.TEMPORAL,
64
+ regex: /\b(yesterday|recently|earlier)\b/i,
65
+ confidence: 0.9,
66
+ label: "temporal"
67
+ },
68
+ {
69
+ type: QueryType.TEMPORAL,
70
+ regex: /\bbefore\b/i,
71
+ confidence: 0.7,
72
+ label: "temporal_before"
73
+ },
74
+ // Factual patterns (WH questions) - after temporal to avoid misclassifying temporal queries
75
+ {
76
+ type: QueryType.FACTUAL,
77
+ regex: /\b(what|who|where)\s+(is|was|are|were)\b/i,
78
+ confidence: 0.95,
79
+ label: "factual_wh"
80
+ },
81
+ // Preference patterns
82
+ {
83
+ type: QueryType.PREFERENCE,
84
+ regex: /\b(prefer|want|style|favorite)\b/i,
85
+ confidence: 0.9,
86
+ label: "preference"
87
+ },
88
+ // Note: 'like' as preference is checked but has lower confidence due to ambiguity
89
+ {
90
+ type: QueryType.PREFERENCE,
91
+ regex: /\bhow do i like\b/i,
92
+ confidence: 0.85,
93
+ label: "preference_like"
94
+ },
95
+ // Project patterns
96
+ {
97
+ type: QueryType.PROJECT,
98
+ regex: /\b(working on|decided|decide|decision)\b/i,
99
+ confidence: 0.9,
100
+ label: "project_specific"
101
+ },
102
+ {
103
+ type: QueryType.PROJECT,
104
+ regex: /\b(project|building|creating|developing)\b/i,
105
+ confidence: 0.85,
106
+ label: "project"
107
+ }
108
+ ];
109
+ // Check each pattern in order
110
+ for (const pattern of patterns) {
111
+ if (pattern.regex.test(normalizedQuery)) {
112
+ return {
113
+ type: pattern.type,
114
+ confidence: pattern.confidence,
115
+ matchedPattern: pattern.label
116
+ };
117
+ }
118
+ }
119
+ // Default to complex query
120
+ return {
121
+ type: QueryType.COMPLEX,
122
+ confidence: 0.5
123
+ };
124
+ }
125
+ /**
126
+ * Smart query router following v3.0 plan retrieval strategy
127
+ *
128
+ * Routing decision tree:
129
+ * 1. Check working memory first (5ms, high confidence threshold)
130
+ * 2. Classify query type with regex
131
+ * 3. Route to appropriate handler:
132
+ * - factual: direct entity lookup
133
+ * - preference: preference retrieval
134
+ * - project: graph traversal with HippoRAG
135
+ * - temporal: time-based filtering
136
+ * - skill: skill library search
137
+ * - complex: hybrid search (dense + sparse + BM25)
138
+ *
139
+ * @param query - The user's query string
140
+ * @param context - Routing context (user, conversation, etc.)
141
+ * @returns Promise resolving to array of memory results
142
+ *
143
+ * @throws Error if query is empty or context is invalid
144
+ */
145
+ export async function retrieve(query, context) {
146
+ // Input validation
147
+ if (!query || query.trim().length === 0) {
148
+ throw new Error("Query cannot be empty");
149
+ }
150
+ if (!context || !context.userId) {
151
+ throw new Error("Valid routing context with userId is required");
152
+ }
153
+ // Step 1: ALWAYS check working memory first (5ms fast path)
154
+ const recentMemories = await checkWorkingMemory(query, context);
155
+ // High similarity threshold suggests cache hit - return immediately
156
+ if (recentMemories.length > 0 && recentMemories[0].similarity > 0.85) {
157
+ console.debug(`[Router] Cache hit in working memory for query: "${query}"`);
158
+ return recentMemories;
159
+ }
160
+ // Step 2: Classify query type using regex patterns
161
+ const classification = classifyQuery(query);
162
+ console.debug(`[Router] Query classified as ${classification.type} ` +
163
+ `(confidence: ${classification.confidence}, pattern: ${classification.matchedPattern})`);
164
+ // Step 3: Route to appropriate handler based on classification
165
+ let results = [];
166
+ switch (classification.type) {
167
+ case QueryType.FACTUAL:
168
+ results = await handleFactualQuery(query, context);
169
+ break;
170
+ case QueryType.PREFERENCE:
171
+ results = await handlePreferenceQuery(query, context);
172
+ break;
173
+ case QueryType.PROJECT:
174
+ results = await handleProjectQuery(query, context);
175
+ break;
176
+ case QueryType.TEMPORAL:
177
+ results = await handleTemporalQuery(query, context);
178
+ break;
179
+ case QueryType.SKILL:
180
+ results = await handleSkillQuery(query, context);
181
+ break;
182
+ case QueryType.COMPLEX:
183
+ default:
184
+ results = await handleComplexQuery(query, context);
185
+ break;
186
+ }
187
+ return results;
188
+ }
189
+ /**
190
+ * Check working memory for recent relevant memories
191
+ *
192
+ * Implementation stub - will integrate with Redis/Hopfield layer
193
+ * Current behavior: returns empty array (no working memory yet)
194
+ *
195
+ * @param query - Search query
196
+ * @param context - Routing context
197
+ * @returns Recent memory results matching query
198
+ */
199
+ async function checkWorkingMemory(query, context) {
200
+ console.debug(`[Router] Checking working memory for: "${query}"`);
201
+ // TODO: Implement Redis working memory search with Hopfield network
202
+ // - Get user's working memory from Redis
203
+ // - Embed query using BGE-large
204
+ // - Perform Hopfield associative recall
205
+ // - Return top-K matches with similarity scores
206
+ return [];
207
+ }
208
+ /**
209
+ * Handle factual queries
210
+ *
211
+ * Pattern: "What is X?", "Who is Y?", "Where is Z?"
212
+ * Handler: Direct entity lookup in semantic memory
213
+ *
214
+ * Implementation stub
215
+ *
216
+ * @param query - The factual query
217
+ * @param context - Routing context
218
+ * @returns Entity information
219
+ */
220
+ async function handleFactualQuery(query, context) {
221
+ console.debug(`[Router] Handling factual query: "${query}"`);
222
+ // TODO: Implement factual query handler
223
+ // 1. Extract entity name from query (using NER or simple heuristics)
224
+ // 2. Lookup entity in semantic memory
225
+ // 3. Retrieve related facts and properties
226
+ // 4. Return with confidence scores
227
+ return [];
228
+ }
229
+ /**
230
+ * Handle preference queries
231
+ *
232
+ * Pattern: "How do I prefer X?", "What style do I like?"
233
+ * Handler: Preference retrieval from semantic memory
234
+ *
235
+ * Implementation stub
236
+ *
237
+ * @param query - The preference query
238
+ * @param context - Routing context
239
+ * @returns User preference information
240
+ */
241
+ async function handlePreferenceQuery(query, context) {
242
+ console.debug(`[Router] Handling preference query: "${query}"`);
243
+ // TODO: Implement preference query handler
244
+ // 1. Extract preference domain from query
245
+ // 2. Search semantic memory for related preference facts
246
+ // 3. Apply temporal decay to weight recent preferences
247
+ // 4. Return ranked by recency and reinforcement
248
+ return [];
249
+ }
250
+ /**
251
+ * Handle project queries
252
+ *
253
+ * Pattern: "What did we decide about X?", "What's the status on Y?"
254
+ * Handler: Graph traversal with HippoRAG personalized PageRank
255
+ *
256
+ * Implementation stub
257
+ *
258
+ * @param query - The project query
259
+ * @param context - Routing context
260
+ * @returns Project-related information via graph traversal
261
+ */
262
+ async function handleProjectQuery(query, context) {
263
+ console.debug(`[Router] Handling project query: "${query}"`);
264
+ // TODO: Implement project query handler
265
+ // 1. Extract project entity name from query
266
+ // 2. Lookup project entity in semantic memory
267
+ // 3. Run HippoRAG personalized PageRank from project node (depth=2)
268
+ // 4. Return connected entities and relationships
269
+ return [];
270
+ }
271
+ /**
272
+ * Handle temporal queries
273
+ *
274
+ * Pattern: "What were we working on last week?", "What was discussed yesterday?"
275
+ * Handler: Time-based filtering from semantic memory
276
+ *
277
+ * Implementation stub
278
+ *
279
+ * @param query - The temporal query
280
+ * @param context - Routing context
281
+ * @returns Memories from specified time range
282
+ */
283
+ async function handleTemporalQuery(query, context) {
284
+ console.debug(`[Router] Handling temporal query: "${query}"`);
285
+ // TODO: Implement temporal query handler
286
+ // 1. Parse temporal references from query
287
+ // 2. Convert to time range (start_date, end_date)
288
+ // 3. Query semantic memory for memories in that range
289
+ // 4. Apply temporal decay based on specificity
290
+ return [];
291
+ }
292
+ /**
293
+ * Handle skill queries
294
+ *
295
+ * Pattern: "Analyze this like before", "Same way as last time"
296
+ * Handler: Skill library semantic search
297
+ *
298
+ * Implementation stub
299
+ *
300
+ * @param query - The skill query
301
+ * @param context - Routing context
302
+ * @returns Matching skills from skill library
303
+ */
304
+ async function handleSkillQuery(query, context) {
305
+ console.debug(`[Router] Handling skill query: "${query}"`);
306
+ // TODO: Implement skill query handler
307
+ // 1. Embed query using BGE-large
308
+ // 2. Search skill library for matching triggers
309
+ // 3. Filter by prerequisites being met in context
310
+ // 4. Return skills ranked by success rate
311
+ return [];
312
+ }
313
+ /**
314
+ * Handle complex queries
315
+ *
316
+ * Pattern: Ambiguous queries that don't match specific patterns
317
+ * Handler: Hybrid search across all representations
318
+ *
319
+ * Hybrid search pipeline:
320
+ * 1. Parallel search: dense embeddings + sparse vectors + BM25
321
+ * 2. Reciprocal Rank Fusion (k=60) to combine results
322
+ * 3. Light reranking with cross-encoder on top-10
323
+ * 4. Return top-5 fused results
324
+ *
325
+ * Implementation stub
326
+ *
327
+ * @param query - The complex query
328
+ * @param context - Routing context
329
+ * @returns Hybrid search results
330
+ */
331
+ async function handleComplexQuery(query, context) {
332
+ console.debug(`[Router] Handling complex query with hybrid search: "${query}"`);
333
+ // TODO: Implement hybrid search
334
+ // 1. Embed query in multiple representations:
335
+ // - Dense: BGE-large embeddings
336
+ // - Sparse: SPLADE++ sparse vectors
337
+ // - Keyword: BM25 tokenization
338
+ //
339
+ // 2. Parallel search in Qdrant:
340
+ // - Dense similarity search (limit: 20)
341
+ // - Sparse similarity search (limit: 20)
342
+ // - BM25 full-text search (limit: 20)
343
+ //
344
+ // 3. Reciprocal Rank Fusion:
345
+ // - Combine ranked lists from three searches
346
+ // - Weight scores using RRF formula with k=60
347
+ //
348
+ // 4. Light reranking:
349
+ // - Use cross-encoder (not ColBERT for speed)
350
+ // - Rerank only top-10 results
351
+ // - Adds ~20ms but significant accuracy gain
352
+ //
353
+ // 5. Return top-5 after reranking
354
+ return [];
355
+ }
356
+ /**
357
+ * Extract entity name from a query
358
+ *
359
+ * Implementation stub for entity extraction
360
+ * Will later integrate with NER or simple heuristics
361
+ */
362
+ export function extractEntityName(query) {
363
+ // TODO: Implement entity extraction
364
+ // Current: just return null
365
+ return null;
366
+ }
367
+ /**
368
+ * Extract domain/category from a query
369
+ *
370
+ * Implementation stub for domain extraction
371
+ * Used for preference and skill queries
372
+ */
373
+ export function extractDomain(query) {
374
+ // TODO: Implement domain extraction
375
+ // Current: just return null
376
+ return null;
377
+ }
378
+ export function parseTimeRange(query) {
379
+ // TODO: Implement temporal reference parsing
380
+ // Current: just return null
381
+ return null;
382
+ }
383
+ //# sourceMappingURL=smart-router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smart-router.js","sourceRoot":"","sources":["../../src/router/smart-router.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Rate Limit Middleware
3
+ *
4
+ * Integrates rate limiting into the MCP server.
5
+ * Implements SEC-HIGH-001 and SEC-HIGH-002 from security audit.
6
+ *
7
+ * Security Features:
8
+ * - Fail-closed behavior when Redis unavailable (SEC-HIGH-002)
9
+ * - Tier-based rate limits
10
+ * - Standard rate limit headers
11
+ * - 429 error responses with Retry-After
12
+ */
13
+ import { Redis } from "ioredis";
14
+ import { RateLimitConfig } from "../utils/rate-limiter.js";
15
+ import { TierName } from "../config/rate-limits.js";
16
+ /**
17
+ * Rate limit headers to include in responses
18
+ */
19
+ export interface RateLimitHeaders {
20
+ "X-RateLimit-Limit": string;
21
+ "X-RateLimit-Remaining": string;
22
+ "X-RateLimit-Reset": string;
23
+ "Retry-After"?: string;
24
+ "X-RateLimit-Bypass"?: string;
25
+ }
26
+ /**
27
+ * Result from rate limit check
28
+ */
29
+ export interface RateLimitCheckResult {
30
+ /** Whether the request is allowed */
31
+ allowed: boolean;
32
+ /** Remaining requests in current window */
33
+ remaining: number;
34
+ /** Unix timestamp when limit resets */
35
+ resetAt: number;
36
+ /** Rate limit headers to include in response */
37
+ headers: RateLimitHeaders;
38
+ }
39
+ /**
40
+ * Rate limit error for 429 responses
41
+ */
42
+ export declare class RateLimitError extends Error {
43
+ readonly statusCode: number;
44
+ readonly retryAfter: number;
45
+ constructor(message: string, statusCode: number, retryAfter: number);
46
+ }
47
+ /**
48
+ * Middleware options
49
+ */
50
+ export interface RateLimitMiddlewareOptions {
51
+ /** Whether to allow requests when Redis is unavailable */
52
+ failOpen: boolean;
53
+ /** Rate limit tier to apply */
54
+ tier: TierName;
55
+ /** Custom limits that override tier defaults */
56
+ customLimits?: Record<string, RateLimitConfig>;
57
+ /** Emergency limit for in-memory fallback */
58
+ emergencyLimit?: number;
59
+ }
60
+ /**
61
+ * Rate Limit Middleware
62
+ *
63
+ * Wraps the RateLimiter class and provides:
64
+ * - Standard HTTP headers
65
+ * - Fail-closed behavior
66
+ * - Error handling for 429 responses
67
+ */
68
+ export declare class RateLimitMiddleware {
69
+ private redis;
70
+ private rateLimiter;
71
+ private options;
72
+ private inMemoryLimits;
73
+ constructor(redis: Redis, options: RateLimitMiddlewareOptions);
74
+ /**
75
+ * Build rate limit configuration from options
76
+ */
77
+ private buildConfig;
78
+ /**
79
+ * Check rate limit for a request
80
+ *
81
+ * @param userId - User identifier
82
+ * @param operation - MCP tool name
83
+ * @returns Rate limit check result
84
+ * @throws RateLimitError if rate limited or Redis unavailable (fail-closed)
85
+ */
86
+ checkRateLimit(userId: string, operation: string): Promise<RateLimitCheckResult>;
87
+ /**
88
+ * Check rate limit using Redis
89
+ */
90
+ private checkRateLimitRedis;
91
+ /**
92
+ * Create bypass result for fail-open mode
93
+ */
94
+ private createBypassResult;
95
+ /**
96
+ * Get current configuration
97
+ */
98
+ getConfig(): Record<string, RateLimitConfig>;
99
+ /**
100
+ * Update tier
101
+ */
102
+ setTier(tier: TierName): void;
103
+ }
104
+ /**
105
+ * Factory function to create rate limit middleware
106
+ *
107
+ * @param redis - Redis client
108
+ * @param options - Middleware options
109
+ */
110
+ export declare function createRateLimitMiddleware(redis: Redis, options: RateLimitMiddlewareOptions): RateLimitMiddleware;
111
+ /**
112
+ * Format rate limit error for MCP response
113
+ */
114
+ export declare function formatRateLimitError(error: RateLimitError, operation: string): {
115
+ error: string;
116
+ retryAfter: number;
117
+ operation: string;
118
+ };
119
+ //# sourceMappingURL=rate-limit-middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit-middleware.d.ts","sourceRoot":"","sources":["../../src/security/rate-limit-middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAGL,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,QAAQ,EAET,MAAM,0BAA0B,CAAC;AAElC;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,uBAAuB,EAAE,MAAM,CAAC;IAChC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,qCAAqC;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,OAAO,EAAE,gBAAgB,CAAC;CAC3B;AAED;;GAEG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACvC,SAAgB,UAAU,EAAE,MAAM,CAAC;IACnC,SAAgB,UAAU,EAAE,MAAM,CAAC;gBAEvB,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;CAWpE;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,0DAA0D;IAC1D,QAAQ,EAAE,OAAO,CAAC;IAClB,+BAA+B;IAC/B,IAAI,EAAE,QAAQ,CAAC;IACf,gDAAgD;IAChD,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC/C,6CAA6C;IAC7C,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,cAAc,CACV;gBAEA,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,0BAA0B;IAe7D;;OAEG;IACH,OAAO,CAAC,WAAW;IAmBnB;;;;;;;OAOG;IACG,cAAc,CAClB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,oBAAoB,CAAC;IA0BhC;;OAEG;YACW,mBAAmB;IA8CjC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAc1B;;OAEG;IACH,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC;IAI5C;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI;CAQ9B;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,0BAA0B,GAClC,mBAAmB,CAErB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,cAAc,EACrB,SAAS,EAAE,MAAM,GAChB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAM1D"}