UNPKG

mnemos-coder

Version:

CLI-based coding agent with graph-based execution loop and terminal UI

175 lines 5.8 kB
/** * API-based embedding service for code semantic search * Uses external embedding models via REST API */ export class ApiEmbedder { config; baseURL; headers; constructor(config) { this.config = config; this.baseURL = config.base_url.endsWith('/') ? config.base_url : config.base_url + '/'; this.headers = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${config.api_key}` }; } /** * Generate embedding for a single text */ async embed(text) { const startTime = Date.now(); try { const response = await this.makeRequest({ input: text, model: this.config.model, encoding_format: 'float' }); if (!response.data || response.data.length === 0) { throw new Error('No embedding data received'); } const embedding = response.data[0].embedding; return { embedding, dimension: embedding.length, processingTime: Date.now() - startTime, model: response.model }; } catch (error) { throw new Error(`Embedding API error: ${error instanceof Error ? error.message : String(error)}`); } } /** * Generate embeddings for multiple texts (batch processing) */ async embedBatch(texts) { const startTime = Date.now(); if (texts.length === 0) { return { embeddings: [], dimension: this.config.dimension, processingTime: 0, model: this.config.model }; } try { // Process in batches to avoid API limits const batchSize = this.config.batch_size || 32; const batches = []; for (let i = 0; i < texts.length; i += batchSize) { batches.push(texts.slice(i, i + batchSize)); } const allEmbeddings = []; let totalTokens = 0; let actualDimension = this.config.dimension; for (const batch of batches) { const response = await this.makeRequest({ input: batch, model: this.config.model, encoding_format: 'float' }); // Extract embeddings and maintain order const batchEmbeddings = response.data .sort((a, b) => a.index - b.index) .map(item => item.embedding); allEmbeddings.push(...batchEmbeddings); if (response.usage) { totalTokens += response.usage.total_tokens; } if (batchEmbeddings.length > 0) { actualDimension = batchEmbeddings[0].length; } // Add small delay between batches to avoid rate limiting if (batches.length > 1) { await new Promise(resolve => setTimeout(resolve, 100)); } } return { embeddings: allEmbeddings, dimension: actualDimension, processingTime: Date.now() - startTime, model: this.config.model, total_tokens: totalTokens }; } catch (error) { throw new Error(`Batch embedding API error: ${error instanceof Error ? error.message : String(error)}`); } } /** * Calculate cosine similarity between two embeddings */ calculateSimilarity(embedding1, embedding2) { if (embedding1.length !== embedding2.length) { throw new Error('Embedding dimensions must match'); } let dotProduct = 0; let norm1 = 0; let norm2 = 0; for (let i = 0; i < embedding1.length; i++) { dotProduct += embedding1[i] * embedding2[i]; norm1 += embedding1[i] * embedding1[i]; norm2 += embedding2[i] * embedding2[i]; } if (norm1 === 0 || norm2 === 0) { return 0; } return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2)); } /** * Get embedding configuration */ getConfig() { return { ...this.config }; } /** * Test API connection */ async testConnection() { const startTime = Date.now(); try { await this.embed('test connection'); const latency = Date.now() - startTime; return { success: true, message: 'Connection successful', latency }; } catch (error) { return { success: false, message: error instanceof Error ? error.message : String(error) }; } } /** * Get model information */ getModelInfo() { return { name: this.config.name, model: this.config.model, dimension: this.config.dimension, baseURL: this.config.base_url }; } /** * Make HTTP request to embedding API */ async makeRequest(payload) { const url = new URL('embeddings', this.baseURL).toString(); const response = await fetch(url, { method: 'POST', headers: this.headers, body: JSON.stringify(payload) }); if (!response.ok) { const errorText = await response.text(); throw new Error(`API request failed (${response.status}): ${errorText}`); } return response.json(); } } //# sourceMappingURL=ApiEmbedder.js.map