@sparkleideas/plugins 3.0.0-alpha.10

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 (80) hide show
  1. package/README.md +401 -0
  2. package/__tests__/collection-manager.test.ts +332 -0
  3. package/__tests__/dependency-graph.test.ts +434 -0
  4. package/__tests__/enhanced-plugin-registry.test.ts +488 -0
  5. package/__tests__/plugin-registry.test.ts +368 -0
  6. package/__tests__/ruvector-bridge.test.ts +2429 -0
  7. package/__tests__/ruvector-integration.test.ts +1602 -0
  8. package/__tests__/ruvector-migrations.test.ts +1099 -0
  9. package/__tests__/ruvector-quantization.test.ts +846 -0
  10. package/__tests__/ruvector-streaming.test.ts +1088 -0
  11. package/__tests__/sdk.test.ts +325 -0
  12. package/__tests__/security.test.ts +348 -0
  13. package/__tests__/utils/ruvector-test-utils.ts +860 -0
  14. package/examples/plugin-creator/index.ts +636 -0
  15. package/examples/plugin-creator/plugin-creator.test.ts +312 -0
  16. package/examples/ruvector/README.md +288 -0
  17. package/examples/ruvector/attention-patterns.ts +394 -0
  18. package/examples/ruvector/basic-usage.ts +288 -0
  19. package/examples/ruvector/docker-compose.yml +75 -0
  20. package/examples/ruvector/gnn-analysis.ts +501 -0
  21. package/examples/ruvector/hyperbolic-hierarchies.ts +557 -0
  22. package/examples/ruvector/init-db.sql +119 -0
  23. package/examples/ruvector/quantization.ts +680 -0
  24. package/examples/ruvector/self-learning.ts +447 -0
  25. package/examples/ruvector/semantic-search.ts +576 -0
  26. package/examples/ruvector/streaming-large-data.ts +507 -0
  27. package/examples/ruvector/transactions.ts +594 -0
  28. package/examples/ruvector-plugins/hook-pattern-library.ts +486 -0
  29. package/examples/ruvector-plugins/index.ts +79 -0
  30. package/examples/ruvector-plugins/intent-router.ts +354 -0
  31. package/examples/ruvector-plugins/mcp-tool-optimizer.ts +424 -0
  32. package/examples/ruvector-plugins/reasoning-bank.ts +657 -0
  33. package/examples/ruvector-plugins/ruvector-plugins.test.ts +518 -0
  34. package/examples/ruvector-plugins/semantic-code-search.ts +498 -0
  35. package/examples/ruvector-plugins/shared/index.ts +20 -0
  36. package/examples/ruvector-plugins/shared/vector-utils.ts +257 -0
  37. package/examples/ruvector-plugins/sona-learning.ts +445 -0
  38. package/package.json +97 -0
  39. package/src/collections/collection-manager.ts +661 -0
  40. package/src/collections/index.ts +56 -0
  41. package/src/collections/official/index.ts +1040 -0
  42. package/src/core/base-plugin.ts +416 -0
  43. package/src/core/plugin-interface.ts +215 -0
  44. package/src/hooks/index.ts +685 -0
  45. package/src/index.ts +378 -0
  46. package/src/integrations/agentic-flow.ts +743 -0
  47. package/src/integrations/index.ts +88 -0
  48. package/src/integrations/ruvector/ARCHITECTURE.md +1245 -0
  49. package/src/integrations/ruvector/attention-advanced.ts +1040 -0
  50. package/src/integrations/ruvector/attention-executor.ts +782 -0
  51. package/src/integrations/ruvector/attention-mechanisms.ts +757 -0
  52. package/src/integrations/ruvector/attention.ts +1063 -0
  53. package/src/integrations/ruvector/gnn.ts +3050 -0
  54. package/src/integrations/ruvector/hyperbolic.ts +1948 -0
  55. package/src/integrations/ruvector/index.ts +394 -0
  56. package/src/integrations/ruvector/migrations/001_create_extension.sql +135 -0
  57. package/src/integrations/ruvector/migrations/002_create_vector_tables.sql +259 -0
  58. package/src/integrations/ruvector/migrations/003_create_indices.sql +328 -0
  59. package/src/integrations/ruvector/migrations/004_create_functions.sql +598 -0
  60. package/src/integrations/ruvector/migrations/005_create_attention_functions.sql +654 -0
  61. package/src/integrations/ruvector/migrations/006_create_gnn_functions.sql +728 -0
  62. package/src/integrations/ruvector/migrations/007_create_hyperbolic_functions.sql +762 -0
  63. package/src/integrations/ruvector/migrations/index.ts +35 -0
  64. package/src/integrations/ruvector/migrations/migrations.ts +647 -0
  65. package/src/integrations/ruvector/quantization.ts +2036 -0
  66. package/src/integrations/ruvector/ruvector-bridge.ts +2000 -0
  67. package/src/integrations/ruvector/self-learning.ts +2376 -0
  68. package/src/integrations/ruvector/streaming.ts +1737 -0
  69. package/src/integrations/ruvector/types.ts +1945 -0
  70. package/src/providers/index.ts +643 -0
  71. package/src/registry/dependency-graph.ts +568 -0
  72. package/src/registry/enhanced-plugin-registry.ts +994 -0
  73. package/src/registry/plugin-registry.ts +604 -0
  74. package/src/sdk/index.ts +563 -0
  75. package/src/security/index.ts +594 -0
  76. package/src/types/index.ts +446 -0
  77. package/src/workers/index.ts +700 -0
  78. package/tmp.json +0 -0
  79. package/tsconfig.json +25 -0
  80. package/vitest.config.ts +23 -0
@@ -0,0 +1,576 @@
1
+ /**
2
+ * RuVector PostgreSQL Bridge - Semantic Code Search Example
3
+ *
4
+ * This example demonstrates:
5
+ * - Embedding code snippets for semantic search
6
+ * - Natural language code queries
7
+ * - Ranking and relevance scoring
8
+ * - Hybrid search (semantic + keyword)
9
+ *
10
+ * Run with: npx ts-node examples/ruvector/semantic-search.ts
11
+ *
12
+ * @module @sparkleideas/plugins/examples/ruvector/semantic-search
13
+ */
14
+
15
+ import {
16
+ createRuVectorBridge,
17
+ type RuVectorBridge,
18
+ type VectorRecord,
19
+ type VectorSearchOptions,
20
+ } from '../../src/integrations/ruvector/index.js';
21
+
22
+ // ============================================================================
23
+ // Configuration
24
+ // ============================================================================
25
+
26
+ const config = {
27
+ connection: {
28
+ host: process.env.POSTGRES_HOST || 'localhost',
29
+ port: parseInt(process.env.POSTGRES_PORT || '5432', 10),
30
+ database: process.env.POSTGRES_DB || 'vectors',
31
+ user: process.env.POSTGRES_USER || 'postgres',
32
+ password: process.env.POSTGRES_PASSWORD || 'postgres',
33
+ },
34
+ dimensions: 768, // Code embedding dimension (e.g., CodeBERT, StarCoder)
35
+ };
36
+
37
+ // ============================================================================
38
+ // Simulated Embedding Model
39
+ // ============================================================================
40
+
41
+ /**
42
+ * Simulated code embedding function.
43
+ * In production, use a proper code embedding model like:
44
+ * - CodeBERT
45
+ * - StarCoder
46
+ * - Code-LLaMA embeddings
47
+ * - OpenAI text-embedding-3-small
48
+ */
49
+ class CodeEmbedder {
50
+ private dimension: number;
51
+ private vocabulary: Map<string, number[]> = new Map();
52
+
53
+ constructor(dimension: number) {
54
+ this.dimension = dimension;
55
+ this.initializeVocabulary();
56
+ }
57
+
58
+ /**
59
+ * Initialize semantic vocabulary for code concepts.
60
+ * This is a simplified simulation - real models use neural networks.
61
+ */
62
+ private initializeVocabulary(): void {
63
+ const concepts = [
64
+ 'function', 'class', 'variable', 'loop', 'condition',
65
+ 'array', 'object', 'string', 'number', 'boolean',
66
+ 'async', 'await', 'promise', 'callback', 'error',
67
+ 'import', 'export', 'module', 'interface', 'type',
68
+ 'auth', 'user', 'password', 'token', 'login',
69
+ 'database', 'query', 'sql', 'insert', 'select',
70
+ 'api', 'http', 'request', 'response', 'endpoint',
71
+ 'test', 'expect', 'mock', 'assert', 'describe',
72
+ ];
73
+
74
+ concepts.forEach((concept, idx) => {
75
+ const embedding = this.createConceptEmbedding(idx, concepts.length);
76
+ this.vocabulary.set(concept, embedding);
77
+ });
78
+ }
79
+
80
+ /**
81
+ * Create a deterministic embedding for a concept.
82
+ */
83
+ private createConceptEmbedding(idx: number, total: number): number[] {
84
+ const embedding = new Array(this.dimension).fill(0);
85
+ const base = (idx / total) * Math.PI * 2;
86
+
87
+ for (let i = 0; i < this.dimension; i++) {
88
+ embedding[i] = Math.sin(base + (i / this.dimension) * Math.PI) * 0.5;
89
+ if (i % 2 === 0) {
90
+ embedding[i] += Math.cos(base * 2 + i * 0.01) * 0.3;
91
+ }
92
+ }
93
+
94
+ return this.normalize(embedding);
95
+ }
96
+
97
+ /**
98
+ * Embed code snippet.
99
+ */
100
+ embed(code: string): number[] {
101
+ const tokens = this.tokenize(code);
102
+ const embedding = new Array(this.dimension).fill(0);
103
+
104
+ // Accumulate embeddings from vocabulary matches
105
+ let matchCount = 0;
106
+ for (const token of tokens) {
107
+ const tokenLower = token.toLowerCase();
108
+ if (this.vocabulary.has(tokenLower)) {
109
+ const tokenEmbedding = this.vocabulary.get(tokenLower)!;
110
+ for (let i = 0; i < this.dimension; i++) {
111
+ embedding[i] += tokenEmbedding[i];
112
+ }
113
+ matchCount++;
114
+ }
115
+ }
116
+
117
+ // Add noise for tokens not in vocabulary
118
+ const unknownRatio = (tokens.length - matchCount) / tokens.length;
119
+ for (let i = 0; i < this.dimension; i++) {
120
+ embedding[i] += (Math.random() * 2 - 1) * unknownRatio * 0.1;
121
+ }
122
+
123
+ return this.normalize(embedding);
124
+ }
125
+
126
+ /**
127
+ * Embed a natural language query.
128
+ */
129
+ embedQuery(query: string): number[] {
130
+ return this.embed(query);
131
+ }
132
+
133
+ /**
134
+ * Tokenize code into meaningful tokens.
135
+ */
136
+ private tokenize(code: string): string[] {
137
+ return code
138
+ .replace(/[^\w\s]/g, ' ')
139
+ .split(/\s+/)
140
+ .filter(t => t.length > 1);
141
+ }
142
+
143
+ /**
144
+ * Normalize vector to unit length.
145
+ */
146
+ private normalize(vec: number[]): number[] {
147
+ const magnitude = Math.sqrt(vec.reduce((sum, v) => sum + v * v, 0));
148
+ if (magnitude === 0) return vec;
149
+ return vec.map(v => v / magnitude);
150
+ }
151
+ }
152
+
153
+ // ============================================================================
154
+ // Sample Code Repository
155
+ // ============================================================================
156
+
157
+ const codeSnippets = [
158
+ {
159
+ id: 'auth-login',
160
+ language: 'typescript',
161
+ filename: 'auth/login.ts',
162
+ code: `
163
+ async function login(username: string, password: string): Promise<AuthToken> {
164
+ const user = await findUserByUsername(username);
165
+ if (!user) {
166
+ throw new AuthenticationError('User not found');
167
+ }
168
+
169
+ const isValid = await verifyPassword(password, user.passwordHash);
170
+ if (!isValid) {
171
+ throw new AuthenticationError('Invalid password');
172
+ }
173
+
174
+ const token = generateJWT({ userId: user.id, role: user.role });
175
+ await saveSession(user.id, token);
176
+
177
+ return { token, expiresIn: 3600 };
178
+ }`,
179
+ tags: ['authentication', 'login', 'jwt', 'security'],
180
+ },
181
+ {
182
+ id: 'auth-middleware',
183
+ language: 'typescript',
184
+ filename: 'middleware/auth.ts',
185
+ code: `
186
+ export function authMiddleware(req: Request, res: Response, next: NextFunction) {
187
+ const token = req.headers.authorization?.replace('Bearer ', '');
188
+
189
+ if (!token) {
190
+ return res.status(401).json({ error: 'No token provided' });
191
+ }
192
+
193
+ try {
194
+ const decoded = verifyJWT(token);
195
+ req.user = decoded;
196
+ next();
197
+ } catch (error) {
198
+ return res.status(403).json({ error: 'Invalid token' });
199
+ }
200
+ }`,
201
+ tags: ['middleware', 'authentication', 'jwt', 'express'],
202
+ },
203
+ {
204
+ id: 'db-query',
205
+ language: 'typescript',
206
+ filename: 'database/query.ts',
207
+ code: `
208
+ async function executeQuery<T>(sql: string, params: unknown[]): Promise<T[]> {
209
+ const client = await pool.connect();
210
+ try {
211
+ const result = await client.query(sql, params);
212
+ return result.rows;
213
+ } catch (error) {
214
+ logger.error('Database query failed', { sql, error });
215
+ throw new DatabaseError('Query execution failed');
216
+ } finally {
217
+ client.release();
218
+ }
219
+ }`,
220
+ tags: ['database', 'postgresql', 'query', 'async'],
221
+ },
222
+ {
223
+ id: 'api-users',
224
+ language: 'typescript',
225
+ filename: 'api/users.ts',
226
+ code: `
227
+ router.get('/users/:id', async (req: Request, res: Response) => {
228
+ const { id } = req.params;
229
+
230
+ const user = await userService.findById(id);
231
+ if (!user) {
232
+ return res.status(404).json({ error: 'User not found' });
233
+ }
234
+
235
+ res.json({
236
+ id: user.id,
237
+ username: user.username,
238
+ email: user.email,
239
+ createdAt: user.createdAt,
240
+ });
241
+ });`,
242
+ tags: ['api', 'rest', 'users', 'express'],
243
+ },
244
+ {
245
+ id: 'test-auth',
246
+ language: 'typescript',
247
+ filename: 'tests/auth.test.ts',
248
+ code: `
249
+ describe('Authentication', () => {
250
+ it('should login with valid credentials', async () => {
251
+ const result = await login('testuser', 'password123');
252
+
253
+ expect(result.token).toBeDefined();
254
+ expect(result.expiresIn).toBe(3600);
255
+ });
256
+
257
+ it('should reject invalid password', async () => {
258
+ await expect(login('testuser', 'wrong'))
259
+ .rejects
260
+ .toThrow('Invalid password');
261
+ });
262
+ });`,
263
+ tags: ['test', 'jest', 'authentication', 'unit-test'],
264
+ },
265
+ {
266
+ id: 'array-utils',
267
+ language: 'typescript',
268
+ filename: 'utils/array.ts',
269
+ code: `
270
+ export function chunk<T>(array: T[], size: number): T[][] {
271
+ const chunks: T[][] = [];
272
+ for (let i = 0; i < array.length; i += size) {
273
+ chunks.push(array.slice(i, i + size));
274
+ }
275
+ return chunks;
276
+ }
277
+
278
+ export function unique<T>(array: T[]): T[] {
279
+ return [...new Set(array)];
280
+ }
281
+
282
+ export function groupBy<T>(array: T[], key: keyof T): Record<string, T[]> {
283
+ return array.reduce((acc, item) => {
284
+ const groupKey = String(item[key]);
285
+ acc[groupKey] = acc[groupKey] || [];
286
+ acc[groupKey].push(item);
287
+ return acc;
288
+ }, {} as Record<string, T[]>);
289
+ }`,
290
+ tags: ['utility', 'array', 'functional'],
291
+ },
292
+ {
293
+ id: 'error-handler',
294
+ language: 'typescript',
295
+ filename: 'middleware/error.ts',
296
+ code: `
297
+ export function errorHandler(
298
+ error: Error,
299
+ req: Request,
300
+ res: Response,
301
+ next: NextFunction
302
+ ) {
303
+ logger.error('Unhandled error', { error, path: req.path });
304
+
305
+ if (error instanceof ValidationError) {
306
+ return res.status(400).json({ error: error.message });
307
+ }
308
+
309
+ if (error instanceof AuthenticationError) {
310
+ return res.status(401).json({ error: error.message });
311
+ }
312
+
313
+ res.status(500).json({ error: 'Internal server error' });
314
+ }`,
315
+ tags: ['error-handling', 'middleware', 'express'],
316
+ },
317
+ {
318
+ id: 'cache-service',
319
+ language: 'typescript',
320
+ filename: 'services/cache.ts',
321
+ code: `
322
+ class CacheService {
323
+ private cache: Map<string, { value: unknown; expiry: number }> = new Map();
324
+
325
+ async get<T>(key: string): Promise<T | null> {
326
+ const entry = this.cache.get(key);
327
+ if (!entry) return null;
328
+
329
+ if (Date.now() > entry.expiry) {
330
+ this.cache.delete(key);
331
+ return null;
332
+ }
333
+
334
+ return entry.value as T;
335
+ }
336
+
337
+ async set(key: string, value: unknown, ttlSeconds: number): Promise<void> {
338
+ this.cache.set(key, {
339
+ value,
340
+ expiry: Date.now() + ttlSeconds * 1000,
341
+ });
342
+ }
343
+ }`,
344
+ tags: ['cache', 'memory', 'service'],
345
+ },
346
+ ];
347
+
348
+ // ============================================================================
349
+ // Main Example
350
+ // ============================================================================
351
+
352
+ async function main(): Promise<void> {
353
+ console.log('RuVector PostgreSQL Bridge - Semantic Code Search Example');
354
+ console.log('=========================================================\n');
355
+
356
+ const bridge: RuVectorBridge = createRuVectorBridge({
357
+ connectionString: `postgresql://${config.connection.user}:${config.connection.password}@${config.connection.host}:${config.connection.port}/${config.connection.database}`,
358
+ });
359
+
360
+ const embedder = new CodeEmbedder(config.dimensions);
361
+
362
+ try {
363
+ await bridge.connect();
364
+ console.log('Connected to PostgreSQL\n');
365
+
366
+ // ========================================================================
367
+ // 1. Create Code Collection
368
+ // ========================================================================
369
+ console.log('1. Creating code collection...');
370
+ await bridge.createCollection('code_snippets', {
371
+ dimensions: config.dimensions,
372
+ distanceMetric: 'cosine',
373
+ indexType: 'hnsw',
374
+ indexParams: { m: 16, efConstruction: 100 },
375
+ });
376
+ console.log(' Collection created!\n');
377
+
378
+ // ========================================================================
379
+ // 2. Index Code Snippets
380
+ // ========================================================================
381
+ console.log('2. Indexing code snippets...');
382
+
383
+ for (const snippet of codeSnippets) {
384
+ const embedding = embedder.embed(snippet.code);
385
+ await bridge.insert('code_snippets', {
386
+ id: snippet.id,
387
+ embedding,
388
+ metadata: {
389
+ language: snippet.language,
390
+ filename: snippet.filename,
391
+ tags: snippet.tags,
392
+ codePreview: snippet.code.slice(0, 100) + '...',
393
+ },
394
+ });
395
+ console.log(` Indexed: ${snippet.filename}`);
396
+ }
397
+ console.log(' All snippets indexed!\n');
398
+
399
+ // ========================================================================
400
+ // 3. Natural Language Code Search
401
+ // ========================================================================
402
+ console.log('3. Natural language search examples:\n');
403
+
404
+ const queries = [
405
+ 'How do I authenticate a user with username and password?',
406
+ 'Show me how to handle errors in Express middleware',
407
+ 'I need to query a PostgreSQL database',
408
+ 'Unit test example for login functionality',
409
+ 'How to implement caching with expiration?',
410
+ ];
411
+
412
+ for (const query of queries) {
413
+ console.log(` Query: "${query}"`);
414
+
415
+ const queryEmbedding = embedder.embedQuery(query);
416
+ const results = await bridge.search('code_snippets', queryEmbedding, {
417
+ k: 2,
418
+ includeMetadata: true,
419
+ includeDistance: true,
420
+ });
421
+
422
+ console.log(' Results:');
423
+ results.forEach((result, i) => {
424
+ const similarity = 1 - (result.distance ?? 0);
425
+ console.log(` ${i + 1}. ${result.metadata?.filename} (similarity: ${(similarity * 100).toFixed(1)}%)`);
426
+ console.log(` Tags: ${(result.metadata?.tags as string[])?.join(', ')}`);
427
+ });
428
+ console.log();
429
+ }
430
+
431
+ // ========================================================================
432
+ // 4. Tag-Filtered Search
433
+ // ========================================================================
434
+ console.log('4. Tag-filtered search (authentication + middleware)...\n');
435
+
436
+ const authQuery = 'verify user credentials and protect routes';
437
+ const authEmbedding = embedder.embedQuery(authQuery);
438
+
439
+ const authResults = await bridge.search('code_snippets', authEmbedding, {
440
+ k: 5,
441
+ includeMetadata: true,
442
+ includeDistance: true,
443
+ filter: {
444
+ tags: { $contains: 'authentication' },
445
+ },
446
+ });
447
+
448
+ console.log(` Query: "${authQuery}"`);
449
+ console.log(' Filtered to: authentication tag');
450
+ console.log(' Results:');
451
+ authResults.forEach((result, i) => {
452
+ const similarity = 1 - (result.distance ?? 0);
453
+ console.log(` ${i + 1}. ${result.metadata?.filename} (similarity: ${(similarity * 100).toFixed(1)}%)`);
454
+ });
455
+ console.log();
456
+
457
+ // ========================================================================
458
+ // 5. Hybrid Search (Semantic + Keyword)
459
+ // ========================================================================
460
+ console.log('5. Hybrid search (semantic + keyword matching)...\n');
461
+
462
+ const hybridQuery = 'async function database';
463
+ const hybridEmbedding = embedder.embedQuery(hybridQuery);
464
+
465
+ // First, get semantic results
466
+ const semanticResults = await bridge.search('code_snippets', hybridEmbedding, {
467
+ k: 10,
468
+ includeMetadata: true,
469
+ includeDistance: true,
470
+ });
471
+
472
+ // Then, boost results that contain the keyword
473
+ const keyword = 'async';
474
+ const hybridResults = semanticResults
475
+ .map(result => {
476
+ const code = codeSnippets.find(s => s.id === result.id)?.code ?? '';
477
+ const keywordMatches = (code.match(new RegExp(keyword, 'gi')) || []).length;
478
+ const semanticScore = 1 - (result.distance ?? 0);
479
+ const keywordBoost = Math.min(keywordMatches * 0.05, 0.2);
480
+ const hybridScore = semanticScore * 0.7 + keywordBoost + 0.1;
481
+
482
+ return { ...result, hybridScore };
483
+ })
484
+ .sort((a, b) => b.hybridScore - a.hybridScore)
485
+ .slice(0, 3);
486
+
487
+ console.log(` Query: "${hybridQuery}"`);
488
+ console.log(' Results (semantic 70% + keyword boost 30%):');
489
+ hybridResults.forEach((result, i) => {
490
+ console.log(` ${i + 1}. ${result.metadata?.filename} (hybrid score: ${(result.hybridScore * 100).toFixed(1)}%)`);
491
+ });
492
+ console.log();
493
+
494
+ // ========================================================================
495
+ // 6. Similar Code Detection
496
+ // ========================================================================
497
+ console.log('6. Finding similar code to a reference snippet...\n');
498
+
499
+ const referenceId = 'auth-login';
500
+ const reference = await bridge.get('code_snippets', referenceId);
501
+
502
+ if (reference) {
503
+ const similarResults = await bridge.search('code_snippets', reference.embedding, {
504
+ k: 4,
505
+ includeMetadata: true,
506
+ includeDistance: true,
507
+ });
508
+
509
+ console.log(` Reference: ${reference.metadata?.filename}`);
510
+ console.log(' Similar code:');
511
+ similarResults
512
+ .filter(r => r.id !== referenceId) // Exclude self
513
+ .forEach((result, i) => {
514
+ const similarity = 1 - (result.distance ?? 0);
515
+ console.log(` ${i + 1}. ${result.metadata?.filename} (similarity: ${(similarity * 100).toFixed(1)}%)`);
516
+ });
517
+ }
518
+ console.log();
519
+
520
+ // ========================================================================
521
+ // 7. Relevance Feedback (Re-ranking)
522
+ // ========================================================================
523
+ console.log('7. Relevance feedback / re-ranking demo...\n');
524
+
525
+ // User marks 'auth-middleware' as relevant for authentication queries
526
+ const relevantId = 'auth-middleware';
527
+ const relevantDoc = await bridge.get('code_snippets', relevantId);
528
+
529
+ if (relevantDoc) {
530
+ // Combine original query with relevant document embedding
531
+ const originalQuery = 'protect API endpoints';
532
+ const originalEmbedding = embedder.embedQuery(originalQuery);
533
+
534
+ // Rocchio algorithm: query' = alpha * query + beta * relevant
535
+ const alpha = 0.7;
536
+ const beta = 0.3;
537
+ const expandedEmbedding = originalEmbedding.map(
538
+ (v, i) => alpha * v + beta * relevantDoc.embedding[i]
539
+ );
540
+
541
+ // Normalize
542
+ const magnitude = Math.sqrt(expandedEmbedding.reduce((s, v) => s + v * v, 0));
543
+ const normalizedEmbedding = expandedEmbedding.map(v => v / magnitude);
544
+
545
+ const rerankedResults = await bridge.search('code_snippets', normalizedEmbedding, {
546
+ k: 3,
547
+ includeMetadata: true,
548
+ includeDistance: true,
549
+ });
550
+
551
+ console.log(` Original query: "${originalQuery}"`);
552
+ console.log(` Relevant feedback: ${relevantDoc.metadata?.filename}`);
553
+ console.log(' Re-ranked results:');
554
+ rerankedResults.forEach((result, i) => {
555
+ const similarity = 1 - (result.distance ?? 0);
556
+ console.log(` ${i + 1}. ${result.metadata?.filename} (similarity: ${(similarity * 100).toFixed(1)}%)`);
557
+ });
558
+ }
559
+
560
+ // ========================================================================
561
+ // Cleanup
562
+ // ========================================================================
563
+ console.log('\n' + '='.repeat(60));
564
+ console.log('Semantic code search example completed!');
565
+ console.log('='.repeat(60));
566
+
567
+ } catch (error) {
568
+ console.error('Error:', error);
569
+ throw error;
570
+ } finally {
571
+ await bridge.disconnect();
572
+ console.log('\nDisconnected from PostgreSQL.');
573
+ }
574
+ }
575
+
576
+ main().catch(console.error);