claude-flow
Version:
Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration
577 lines (501 loc) • 18.5 kB
text/typescript
/**
* RuVector PostgreSQL Bridge - Semantic Code Search Example
*
* This example demonstrates:
* - Embedding code snippets for semantic search
* - Natural language code queries
* - Ranking and relevance scoring
* - Hybrid search (semantic + keyword)
*
* Run with: npx ts-node examples/ruvector/semantic-search.ts
*
* @module @claude-flow/plugins/examples/ruvector/semantic-search
*/
import {
createRuVectorBridge,
type RuVectorBridge,
type VectorRecord,
type VectorSearchOptions,
} from '../../src/integrations/ruvector/index.js';
// ============================================================================
// Configuration
// ============================================================================
const config = {
connection: {
host: process.env.POSTGRES_HOST || 'localhost',
port: parseInt(process.env.POSTGRES_PORT || '5432', 10),
database: process.env.POSTGRES_DB || 'vectors',
user: process.env.POSTGRES_USER || 'postgres',
password: process.env.POSTGRES_PASSWORD || 'postgres',
},
dimensions: 768, // Code embedding dimension (e.g., CodeBERT, StarCoder)
};
// ============================================================================
// Simulated Embedding Model
// ============================================================================
/**
* Simulated code embedding function.
* In production, use a proper code embedding model like:
* - CodeBERT
* - StarCoder
* - Code-LLaMA embeddings
* - OpenAI text-embedding-3-small
*/
class CodeEmbedder {
private dimension: number;
private vocabulary: Map<string, number[]> = new Map();
constructor(dimension: number) {
this.dimension = dimension;
this.initializeVocabulary();
}
/**
* Initialize semantic vocabulary for code concepts.
* This is a simplified simulation - real models use neural networks.
*/
private initializeVocabulary(): void {
const concepts = [
'function', 'class', 'variable', 'loop', 'condition',
'array', 'object', 'string', 'number', 'boolean',
'async', 'await', 'promise', 'callback', 'error',
'import', 'export', 'module', 'interface', 'type',
'auth', 'user', 'password', 'token', 'login',
'database', 'query', 'sql', 'insert', 'select',
'api', 'http', 'request', 'response', 'endpoint',
'test', 'expect', 'mock', 'assert', 'describe',
];
concepts.forEach((concept, idx) => {
const embedding = this.createConceptEmbedding(idx, concepts.length);
this.vocabulary.set(concept, embedding);
});
}
/**
* Create a deterministic embedding for a concept.
*/
private createConceptEmbedding(idx: number, total: number): number[] {
const embedding = new Array(this.dimension).fill(0);
const base = (idx / total) * Math.PI * 2;
for (let i = 0; i < this.dimension; i++) {
embedding[i] = Math.sin(base + (i / this.dimension) * Math.PI) * 0.5;
if (i % 2 === 0) {
embedding[i] += Math.cos(base * 2 + i * 0.01) * 0.3;
}
}
return this.normalize(embedding);
}
/**
* Embed code snippet.
*/
embed(code: string): number[] {
const tokens = this.tokenize(code);
const embedding = new Array(this.dimension).fill(0);
// Accumulate embeddings from vocabulary matches
let matchCount = 0;
for (const token of tokens) {
const tokenLower = token.toLowerCase();
if (this.vocabulary.has(tokenLower)) {
const tokenEmbedding = this.vocabulary.get(tokenLower)!;
for (let i = 0; i < this.dimension; i++) {
embedding[i] += tokenEmbedding[i];
}
matchCount++;
}
}
// Add noise for tokens not in vocabulary
const unknownRatio = (tokens.length - matchCount) / tokens.length;
for (let i = 0; i < this.dimension; i++) {
embedding[i] += (Math.random() * 2 - 1) * unknownRatio * 0.1;
}
return this.normalize(embedding);
}
/**
* Embed a natural language query.
*/
embedQuery(query: string): number[] {
return this.embed(query);
}
/**
* Tokenize code into meaningful tokens.
*/
private tokenize(code: string): string[] {
return code
.replace(/[^\w\s]/g, ' ')
.split(/\s+/)
.filter(t => t.length > 1);
}
/**
* Normalize vector to unit length.
*/
private normalize(vec: number[]): number[] {
const magnitude = Math.sqrt(vec.reduce((sum, v) => sum + v * v, 0));
if (magnitude === 0) return vec;
return vec.map(v => v / magnitude);
}
}
// ============================================================================
// Sample Code Repository
// ============================================================================
const codeSnippets = [
{
id: 'auth-login',
language: 'typescript',
filename: 'auth/login.ts',
code: `
async function login(username: string, password: string): Promise<AuthToken> {
const user = await findUserByUsername(username);
if (!user) {
throw new AuthenticationError('User not found');
}
const isValid = await verifyPassword(password, user.passwordHash);
if (!isValid) {
throw new AuthenticationError('Invalid password');
}
const token = generateJWT({ userId: user.id, role: user.role });
await saveSession(user.id, token);
return { token, expiresIn: 3600 };
}`,
tags: ['authentication', 'login', 'jwt', 'security'],
},
{
id: 'auth-middleware',
language: 'typescript',
filename: 'middleware/auth.ts',
code: `
export function authMiddleware(req: Request, res: Response, next: NextFunction) {
const token = req.headers.authorization?.replace('Bearer ', '');
if (!token) {
return res.status(401).json({ error: 'No token provided' });
}
try {
const decoded = verifyJWT(token);
req.user = decoded;
next();
} catch (error) {
return res.status(403).json({ error: 'Invalid token' });
}
}`,
tags: ['middleware', 'authentication', 'jwt', 'express'],
},
{
id: 'db-query',
language: 'typescript',
filename: 'database/query.ts',
code: `
async function executeQuery<T>(sql: string, params: unknown[]): Promise<T[]> {
const client = await pool.connect();
try {
const result = await client.query(sql, params);
return result.rows;
} catch (error) {
logger.error('Database query failed', { sql, error });
throw new DatabaseError('Query execution failed');
} finally {
client.release();
}
}`,
tags: ['database', 'postgresql', 'query', 'async'],
},
{
id: 'api-users',
language: 'typescript',
filename: 'api/users.ts',
code: `
router.get('/users/:id', async (req: Request, res: Response) => {
const { id } = req.params;
const user = await userService.findById(id);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
res.json({
id: user.id,
username: user.username,
email: user.email,
createdAt: user.createdAt,
});
});`,
tags: ['api', 'rest', 'users', 'express'],
},
{
id: 'test-auth',
language: 'typescript',
filename: 'tests/auth.test.ts',
code: `
describe('Authentication', () => {
it('should login with valid credentials', async () => {
const result = await login('testuser', 'password123');
expect(result.token).toBeDefined();
expect(result.expiresIn).toBe(3600);
});
it('should reject invalid password', async () => {
await expect(login('testuser', 'wrong'))
.rejects
.toThrow('Invalid password');
});
});`,
tags: ['test', 'jest', 'authentication', 'unit-test'],
},
{
id: 'array-utils',
language: 'typescript',
filename: 'utils/array.ts',
code: `
export function chunk<T>(array: T[], size: number): T[][] {
const chunks: T[][] = [];
for (let i = 0; i < array.length; i += size) {
chunks.push(array.slice(i, i + size));
}
return chunks;
}
export function unique<T>(array: T[]): T[] {
return [...new Set(array)];
}
export function groupBy<T>(array: T[], key: keyof T): Record<string, T[]> {
return array.reduce((acc, item) => {
const groupKey = String(item[key]);
acc[groupKey] = acc[groupKey] || [];
acc[groupKey].push(item);
return acc;
}, {} as Record<string, T[]>);
}`,
tags: ['utility', 'array', 'functional'],
},
{
id: 'error-handler',
language: 'typescript',
filename: 'middleware/error.ts',
code: `
export function errorHandler(
error: Error,
req: Request,
res: Response,
next: NextFunction
) {
logger.error('Unhandled error', { error, path: req.path });
if (error instanceof ValidationError) {
return res.status(400).json({ error: error.message });
}
if (error instanceof AuthenticationError) {
return res.status(401).json({ error: error.message });
}
res.status(500).json({ error: 'Internal server error' });
}`,
tags: ['error-handling', 'middleware', 'express'],
},
{
id: 'cache-service',
language: 'typescript',
filename: 'services/cache.ts',
code: `
class CacheService {
private cache: Map<string, { value: unknown; expiry: number }> = new Map();
async get<T>(key: string): Promise<T | null> {
const entry = this.cache.get(key);
if (!entry) return null;
if (Date.now() > entry.expiry) {
this.cache.delete(key);
return null;
}
return entry.value as T;
}
async set(key: string, value: unknown, ttlSeconds: number): Promise<void> {
this.cache.set(key, {
value,
expiry: Date.now() + ttlSeconds * 1000,
});
}
}`,
tags: ['cache', 'memory', 'service'],
},
];
// ============================================================================
// Main Example
// ============================================================================
async function main(): Promise<void> {
console.log('RuVector PostgreSQL Bridge - Semantic Code Search Example');
console.log('=========================================================\n');
const bridge: RuVectorBridge = createRuVectorBridge({
connectionString: `postgresql://${config.connection.user}:${config.connection.password}@${config.connection.host}:${config.connection.port}/${config.connection.database}`,
});
const embedder = new CodeEmbedder(config.dimensions);
try {
await bridge.connect();
console.log('Connected to PostgreSQL\n');
// ========================================================================
// 1. Create Code Collection
// ========================================================================
console.log('1. Creating code collection...');
await bridge.createCollection('code_snippets', {
dimensions: config.dimensions,
distanceMetric: 'cosine',
indexType: 'hnsw',
indexParams: { m: 16, efConstruction: 100 },
});
console.log(' Collection created!\n');
// ========================================================================
// 2. Index Code Snippets
// ========================================================================
console.log('2. Indexing code snippets...');
for (const snippet of codeSnippets) {
const embedding = embedder.embed(snippet.code);
await bridge.insert('code_snippets', {
id: snippet.id,
embedding,
metadata: {
language: snippet.language,
filename: snippet.filename,
tags: snippet.tags,
codePreview: snippet.code.slice(0, 100) + '...',
},
});
console.log(` Indexed: ${snippet.filename}`);
}
console.log(' All snippets indexed!\n');
// ========================================================================
// 3. Natural Language Code Search
// ========================================================================
console.log('3. Natural language search examples:\n');
const queries = [
'How do I authenticate a user with username and password?',
'Show me how to handle errors in Express middleware',
'I need to query a PostgreSQL database',
'Unit test example for login functionality',
'How to implement caching with expiration?',
];
for (const query of queries) {
console.log(` Query: "${query}"`);
const queryEmbedding = embedder.embedQuery(query);
const results = await bridge.search('code_snippets', queryEmbedding, {
k: 2,
includeMetadata: true,
includeDistance: true,
});
console.log(' Results:');
results.forEach((result, i) => {
const similarity = 1 - (result.distance ?? 0);
console.log(` ${i + 1}. ${result.metadata?.filename} (similarity: ${(similarity * 100).toFixed(1)}%)`);
console.log(` Tags: ${(result.metadata?.tags as string[])?.join(', ')}`);
});
console.log();
}
// ========================================================================
// 4. Tag-Filtered Search
// ========================================================================
console.log('4. Tag-filtered search (authentication + middleware)...\n');
const authQuery = 'verify user credentials and protect routes';
const authEmbedding = embedder.embedQuery(authQuery);
const authResults = await bridge.search('code_snippets', authEmbedding, {
k: 5,
includeMetadata: true,
includeDistance: true,
filter: {
tags: { $contains: 'authentication' },
},
});
console.log(` Query: "${authQuery}"`);
console.log(' Filtered to: authentication tag');
console.log(' Results:');
authResults.forEach((result, i) => {
const similarity = 1 - (result.distance ?? 0);
console.log(` ${i + 1}. ${result.metadata?.filename} (similarity: ${(similarity * 100).toFixed(1)}%)`);
});
console.log();
// ========================================================================
// 5. Hybrid Search (Semantic + Keyword)
// ========================================================================
console.log('5. Hybrid search (semantic + keyword matching)...\n');
const hybridQuery = 'async function database';
const hybridEmbedding = embedder.embedQuery(hybridQuery);
// First, get semantic results
const semanticResults = await bridge.search('code_snippets', hybridEmbedding, {
k: 10,
includeMetadata: true,
includeDistance: true,
});
// Then, boost results that contain the keyword
const keyword = 'async';
const hybridResults = semanticResults
.map(result => {
const code = codeSnippets.find(s => s.id === result.id)?.code ?? '';
const keywordMatches = (code.match(new RegExp(keyword, 'gi')) || []).length;
const semanticScore = 1 - (result.distance ?? 0);
const keywordBoost = Math.min(keywordMatches * 0.05, 0.2);
const hybridScore = semanticScore * 0.7 + keywordBoost + 0.1;
return { ...result, hybridScore };
})
.sort((a, b) => b.hybridScore - a.hybridScore)
.slice(0, 3);
console.log(` Query: "${hybridQuery}"`);
console.log(' Results (semantic 70% + keyword boost 30%):');
hybridResults.forEach((result, i) => {
console.log(` ${i + 1}. ${result.metadata?.filename} (hybrid score: ${(result.hybridScore * 100).toFixed(1)}%)`);
});
console.log();
// ========================================================================
// 6. Similar Code Detection
// ========================================================================
console.log('6. Finding similar code to a reference snippet...\n');
const referenceId = 'auth-login';
const reference = await bridge.get('code_snippets', referenceId);
if (reference) {
const similarResults = await bridge.search('code_snippets', reference.embedding, {
k: 4,
includeMetadata: true,
includeDistance: true,
});
console.log(` Reference: ${reference.metadata?.filename}`);
console.log(' Similar code:');
similarResults
.filter(r => r.id !== referenceId) // Exclude self
.forEach((result, i) => {
const similarity = 1 - (result.distance ?? 0);
console.log(` ${i + 1}. ${result.metadata?.filename} (similarity: ${(similarity * 100).toFixed(1)}%)`);
});
}
console.log();
// ========================================================================
// 7. Relevance Feedback (Re-ranking)
// ========================================================================
console.log('7. Relevance feedback / re-ranking demo...\n');
// User marks 'auth-middleware' as relevant for authentication queries
const relevantId = 'auth-middleware';
const relevantDoc = await bridge.get('code_snippets', relevantId);
if (relevantDoc) {
// Combine original query with relevant document embedding
const originalQuery = 'protect API endpoints';
const originalEmbedding = embedder.embedQuery(originalQuery);
// Rocchio algorithm: query' = alpha * query + beta * relevant
const alpha = 0.7;
const beta = 0.3;
const expandedEmbedding = originalEmbedding.map(
(v, i) => alpha * v + beta * relevantDoc.embedding[i]
);
// Normalize
const magnitude = Math.sqrt(expandedEmbedding.reduce((s, v) => s + v * v, 0));
const normalizedEmbedding = expandedEmbedding.map(v => v / magnitude);
const rerankedResults = await bridge.search('code_snippets', normalizedEmbedding, {
k: 3,
includeMetadata: true,
includeDistance: true,
});
console.log(` Original query: "${originalQuery}"`);
console.log(` Relevant feedback: ${relevantDoc.metadata?.filename}`);
console.log(' Re-ranked results:');
rerankedResults.forEach((result, i) => {
const similarity = 1 - (result.distance ?? 0);
console.log(` ${i + 1}. ${result.metadata?.filename} (similarity: ${(similarity * 100).toFixed(1)}%)`);
});
}
// ========================================================================
// Cleanup
// ========================================================================
console.log('\n' + '='.repeat(60));
console.log('Semantic code search example completed!');
console.log('='.repeat(60));
} catch (error) {
console.error('Error:', error);
throw error;
} finally {
await bridge.disconnect();
console.log('\nDisconnected from PostgreSQL.');
}
}
main().catch(console.error);