UNPKG

task-engine-ai-core

Version:

Revolutionary AI-driven task management system with complete transformation trilogy: Frontend v0.1.0, Backend v0.2.0, CLI v0.3.0 - Enterprise-grade performance with 95% improvements

352 lines (307 loc) 11.7 kB
/** * IDE AI Provider * Implements BaseAIProvider interface for IDE-based AI agents */ import { BaseAIProvider } from './base-provider.js'; import IDEAgentInterface from '../bridge/ide-agent-interface.js'; import BridgeConfig from '../bridge/bridge-config.js'; import logger from '../../mcp-server/src/logger.js'; export class IDEAIProvider extends BaseAIProvider { constructor() { super(); this.name = 'IDE Agent'; this.agentInterface = null; this.bridgeConfig = null; this.connected = false; this.capabilities = new Set(); this.connectionAttempts = 0; this.maxConnectionAttempts = 3; this.reconnectDelay = 1000; } /** * Override auth validation - IDE provider doesn't need API keys */ validateAuth(params) { // IDE provider uses the IDE's built-in authentication // No API key required if (!this.connected) { throw new Error('IDE agent not connected. Please ensure bridge is running.'); } } /** * Get IDE agent client */ getClient(params) { if (!this.agentInterface) { throw new Error('IDE agent interface not initialized'); } // Return a client-like interface that wraps the IDE agent return { interface: this.agentInterface, ideType: params.ideType || 'cursor', sessionId: params.sessionId }; } /** * Initialize connection to IDE agent */ async initialize(options = {}) { try { // Load bridge configuration this.bridgeConfig = new BridgeConfig(); await this.bridgeConfig.load(); // Auto-detect IDE if not specified let ideType = options.ideType; if (!ideType || ideType === 'auto-detect') { const detection = await this.bridgeConfig.detectIDE(); ideType = detection.detected ? detection.type : 'cursor'; logger.info(`Auto-detected IDE: ${ideType}`); } // Initialize agent interface this.agentInterface = new IDEAgentInterface({ ideType, agentEndpoint: options.agentEndpoint, sessionId: options.sessionId, responseTimeout: this.bridgeConfig.get('ide.connectionTimeout') || 5000 }); await this.agentInterface.initialize(); this.connected = true; this.capabilities = this.agentInterface.capabilities; this.connectionAttempts = 0; logger.info(`IDE AI Provider initialized for ${ideType}`); return this; } catch (error) { this.connectionAttempts++; logger.error(`Failed to initialize IDE AI Provider (attempt ${this.connectionAttempts}):`, error); // Try to reconnect if enabled and within limits if (this.connectionAttempts < this.maxConnectionAttempts && this.bridgeConfig?.get('bridge.autoRestart')) { logger.info(`Retrying connection in ${this.reconnectDelay}ms...`); await new Promise(resolve => setTimeout(resolve, this.reconnectDelay)); this.reconnectDelay *= 2; // Exponential backoff return this.initialize(options); } throw error; } } /** * Generate text using IDE agent */ async generateText(params) { try { this.validateParams(params); this.validateMessages(params.messages); logger.debug(`Generating text via IDE agent with model: ${params.modelId}`); const result = await this.agentInterface.sendRequest({ type: 'generate-text', payload: { messages: params.messages, maxTokens: params.maxTokens, temperature: params.temperature, modelId: params.modelId } }); logger.debug('IDE agent generateText completed successfully'); return { text: result.text, usage: { inputTokens: result.usage?.inputTokens || 0, outputTokens: result.usage?.outputTokens || 0, totalTokens: result.usage?.totalTokens || 0 }, model: result.model, provider: 'ide-agent' }; } catch (error) { this.handleError('text generation via IDE agent', error); } } /** * Stream text using IDE agent */ async streamText(params) { try { this.validateParams(params); this.validateMessages(params.messages); logger.debug('Streaming text via IDE agent'); // For now, IDE agents may not support streaming // Fall back to regular generation and simulate streaming const result = await this.generateText(params); // Create a simple stream-like interface const stream = { textStream: this.createTextStream(result.text), usage: result.usage, model: result.model, provider: 'ide-agent' }; logger.debug('IDE agent streamText completed successfully'); return stream; } catch (error) { this.handleError('text streaming via IDE agent', error); } } /** * Generate structured object using IDE agent */ async generateObject(params) { try { this.validateParams(params); this.validateMessages(params.messages); if (!params.schema) { throw new Error('Schema is required for object generation'); } if (!params.objectName) { throw new Error('Object name is required for object generation'); } logger.debug(`Generating object '${params.objectName}' via IDE agent`); const result = await this.agentInterface.sendRequest({ type: 'generate-object', payload: { messages: params.messages, schema: params.schema, objectName: params.objectName, maxTokens: params.maxTokens, temperature: params.temperature, modelId: params.modelId } }); logger.debug('IDE agent generateObject completed successfully'); return { object: result.object, usage: { inputTokens: result.usage?.inputTokens || 0, outputTokens: result.usage?.outputTokens || 0, totalTokens: result.usage?.totalTokens || 0 }, model: result.model, provider: 'ide-agent' }; } catch (error) { this.handleError('object generation via IDE agent', error); } } /** * Create a simple text stream from complete text */ createTextStream(text) { const chunks = text.split(' '); let index = 0; return { async *[Symbol.asyncIterator]() { for (const chunk of chunks) { yield { type: 'text-delta', textDelta: chunk + ' ' }; // Small delay to simulate streaming await new Promise(resolve => setTimeout(resolve, 10)); } yield { type: 'finish', finishReason: 'stop' }; } }; } /** * Check if IDE agent supports a specific capability */ hasCapability(capability) { return this.capabilities.has(capability); } /** * Get available models from IDE */ async getAvailableModels() { if (!this.agentInterface) { return []; } // This would query the IDE for available models // For now, return common IDE models const ideModels = { cursor: [ { id: 'cursor-claude-3.5-sonnet', name: 'Claude 3.5 Sonnet (Cursor)' }, { id: 'cursor-gpt-4', name: 'GPT-4 (Cursor)' }, { id: 'cursor-claude-3-opus', name: 'Claude 3 Opus (Cursor)' } ], vscode: [ { id: 'copilot-gpt-4', name: 'GitHub Copilot GPT-4' }, { id: 'copilot-gpt-3.5', name: 'GitHub Copilot GPT-3.5' } ], windsurf: [ { id: 'windsurf-claude-3.5-sonnet', name: 'Claude 3.5 Sonnet (Windsurf)' }, { id: 'windsurf-gpt-4', name: 'GPT-4 (Windsurf)' } ] }; const ideType = this.agentInterface.ideType; return ideModels[ideType] || []; } /** * Get current IDE agent status */ getStatus() { return { name: this.name, connected: this.connected, ideType: this.agentInterface?.ideType || 'unknown', capabilities: Array.from(this.capabilities), activeModel: this.agentInterface?.getActiveModel() || 'unknown', agentStatus: this.agentInterface?.getStatus() || null }; } /** * Disconnect from IDE agent */ async disconnect() { if (this.agentInterface) { await this.agentInterface.disconnect(); } this.connected = false; this.capabilities.clear(); logger.info('IDE AI Provider disconnected'); } /** * Test connection to IDE agent */ async testConnection() { try { if (!this.connected) { throw new Error('Not connected to IDE agent'); } const testResult = await this.generateText({ modelId: 'test', messages: [{ role: 'user', content: 'Test connection' }], maxTokens: 10, temperature: 0.1 }); return { success: true, model: testResult.model, provider: testResult.provider, responseTime: Date.now() }; } catch (error) { return { success: false, error: error.message, responseTime: Date.now() }; } } /** * Override error handling to provide IDE-specific context */ handleError(operation, error) { const ideContext = this.agentInterface ? { ideType: this.agentInterface.ideType, connected: this.connected, capabilities: Array.from(this.capabilities) } : {}; logger.error(`IDE AI Provider error during ${operation}:`, { error: error.message, stack: error.stack, ideContext }); // Enhance error message with IDE-specific guidance let enhancedMessage = error.message; if (!this.connected) { enhancedMessage += ' (IDE agent not connected - ensure WebSocket bridge is running)'; } throw new Error(enhancedMessage); } } export default IDEAIProvider;