UNPKG

@wernerthiago/teo

Version:

Test Execution Optimizer

167 lines (140 loc) 4.36 kB
/** * Ollama Provider * Integration with local Ollama models */ import axios from 'axios' import BaseAIProvider from './base-provider.js' import logger from '../core/logger.js' export class OllamaProvider extends BaseAIProvider { constructor(config) { super(config) this.endpoint = config.endpoint || 'http://localhost:11434' this.model = config.model || 'codellama:7b' // Ollama typically needs longer timeouts for local inference this.timeout = config.timeout || 60000 logger.debug('Ollama provider initialized', { endpoint: this.endpoint, model: this.model }) } async analyzeImpact(prompt, options = {}) { return this.withRetry(async () => { const systemPrompt = 'You are an expert software engineer specializing in test impact analysis. Provide precise, actionable analysis in the requested JSON format.' const fullPrompt = `${systemPrompt}\n\n${prompt}` const response = await axios.post( `${this.endpoint}/api/generate`, { model: this.model, prompt: fullPrompt, stream: false, options: { temperature: this.temperature, num_predict: this.maxTokens } }, { timeout: this.timeout, headers: this.getHeaders() } ) const content = response.data.response if (!content) { throw new Error('Empty response from Ollama') } // Track usage this.trackUsage({ totalTokens: response.data.eval_count || 0, promptTokens: response.data.prompt_eval_count || 0 }) return content }, { model: this.model, endpoint: this.endpoint }) } async validateConnection() { try { // Check if Ollama is running const response = await axios.get(`${this.endpoint}/api/tags`, { timeout: 5000 }) // Check if our model is available const models = response.data.models || [] const modelExists = models.some(m => m.name === this.model) if (!modelExists) { logger.warn('Ollama model not found', { model: this.model, availableModels: models.map(m => m.name) }) return false } logger.info('Ollama connection validated', { endpoint: this.endpoint, model: this.model }) return true } catch (error) { logger.error('Ollama connection validation failed', { error: error.message, endpoint: this.endpoint, model: this.model }) return false } } async listAvailableModels() { try { const response = await axios.get(`${this.endpoint}/api/tags`) return response.data.models || [] } catch (error) { logger.error('Failed to list Ollama models', { error: error.message }) return [] } } async pullModel(modelName) { try { logger.info('Pulling Ollama model', { model: modelName }) const response = await axios.post( `${this.endpoint}/api/pull`, { name: modelName }, { timeout: 300000 } // 5 minutes for model download ) logger.info('Ollama model pulled successfully', { model: modelName }) return true } catch (error) { logger.error('Failed to pull Ollama model', { model: modelName, error: error.message }) return false } } getHeaders() { return { ...super.getHeaders(), 'Accept': 'application/json' } } trackUsage(usage) { if (usage) { this.totalTokens = (this.totalTokens || 0) + (usage.totalTokens || 0) this.totalRequests = (this.totalRequests || 0) + 1 logger.debug('Ollama usage tracked', { promptTokens: usage.promptTokens, totalTokens: usage.totalTokens }) } } shouldNotRetry(error) { // Ollama-specific error patterns const ollamaNoRetryPatterns = [ 'model not found', 'invalid model', 'connection refused', 'service unavailable' ] const errorMessage = error.message.toLowerCase() const ollamaSpecific = ollamaNoRetryPatterns.some(pattern => errorMessage.includes(pattern) ) return ollamaSpecific || super.shouldNotRetry(error) } } export default OllamaProvider