@semantest/chrome-extension
Version:
Browser extension for ChatGPT-buddy - AI automation extension built on Web-Buddy framework
1,678 lines (1,416 loc) • 106 kB
text/typescript
/**
* @fileoverview ChatGPT Buddy Plugin Implementation
* @description AI-powered automation plugin for ChatGPT and language models
*/
import {
WebBuddyPlugin,
PluginMetadata,
PluginCapabilities,
PluginContext,
PluginState,
PluginConfiguration,
PluginUIComponent,
PluginMenuItem,
WebBuddyContract,
PluginEvent,
ContractCapability
} from './plugin-interface';
/**
* ChatGPT-specific plugin configuration
*/
interface ChatGPTPluginConfiguration extends PluginConfiguration {
settings: {
// AI Model Preferences
preferredModel: 'gpt-4' | 'gpt-4-turbo' | 'gpt-3.5-turbo' | 'claude-3-opus' | 'claude-3-sonnet';
fallbackModel: string;
// Training Settings
enableTrainingMode: boolean;
autoLearnPatterns: boolean;
trainingConfidenceThreshold: number;
// Performance Settings
enablePatternRecognition: boolean;
enableAIInsights: boolean;
cacheResponses: boolean;
maxResponseTime: number;
// UI Preferences
showTrainingOverlay: boolean;
enableKeyboardShortcuts: boolean;
notificationLevel: 'minimal' | 'normal' | 'verbose';
// API Configuration
apiKeys: {
openai?: string;
anthropic?: string;
};
rateLimits: {
requestsPerMinute: number;
maxDailyCost: number;
};
};
}
/**
* ChatGPT Plugin Events
*/
export const ChatGPTPluginEvents = {
// AI Interaction Events
AI_INTERACTION_REQUESTED: 'chatgpt:interaction:requested',
AI_RESPONSE_RECEIVED: 'chatgpt:response:received',
AI_MODEL_SWITCHED: 'chatgpt:model:switched',
// Training Events
TRAINING_MODE_ENABLED: 'chatgpt:training:enabled',
TRAINING_PATTERN_LEARNED: 'chatgpt:training:pattern:learned',
TRAINING_SESSION_COMPLETED: 'chatgpt:training:session:completed',
// Automation Events
CHATGPT_MESSAGE_SENT: 'chatgpt:message:sent',
CHATGPT_RESPONSE_EXTRACTED: 'chatgpt:response:extracted',
CONVERSATION_STARTED: 'chatgpt:conversation:started',
// Performance Events
AI_PERFORMANCE_UPDATED: 'chatgpt:performance:updated',
OPTIMIZATION_SUGGESTED: 'chatgpt:optimization:suggested'
} as const;
/**
* ChatGPT Web Application Contracts
*/
const chatGPTContracts: WebBuddyContract[] = [
{
version: "1.0.0",
domain: "chat.openai.com",
title: "ChatGPT Interface Contract",
description: "Automation contract for ChatGPT web interface",
capabilities: {
sendMessage: {
type: "action",
description: "Send a message to ChatGPT",
selector: "textarea[data-id='root']",
parameters: [
{
name: "message",
type: "string",
description: "Message to send to ChatGPT",
required: true
}
],
returnType: {
type: "object",
description: "Send operation result"
}
},
getResponse: {
type: "query",
description: "Extract ChatGPT's latest response",
selector: "[data-message-author-role='assistant']:last-child",
returnType: {
type: "string",
description: "ChatGPT's response text"
}
},
startNewConversation: {
type: "action",
description: "Start a new conversation",
selector: "[data-testid='new-chat-button'], .text-token-text-primary",
returnType: {
type: "void",
description: "New conversation started"
}
},
selectModel: {
type: "action",
description: "Select GPT model",
selector: "[data-testid='model-selector']",
parameters: [
{
name: "model",
type: "string",
description: "Model to select (gpt-4, gpt-3.5-turbo, etc.)",
required: true,
enum: ["gpt-4", "gpt-4-turbo", "gpt-3.5-turbo"]
}
]
},
getConversationHistory: {
type: "query",
description: "Get the full conversation history",
selector: "[data-testid='conversation-turn']",
returnType: {
type: "array",
description: "Array of conversation messages"
}
},
enableBrowsing: {
type: "action",
description: "Enable web browsing capability",
selector: "[data-testid='browsing-toggle']"
},
enablePlugins: {
type: "action",
description: "Enable ChatGPT plugins",
selector: "[data-testid='plugins-toggle']"
}
},
context: {
urlPatterns: [
"https://chat.openai.com/*",
"https://chatgpt.com/*"
],
accessibility: {
ariaCompliant: true,
keyboardNavigation: true
},
performance: {
maxExecutionTime: 30000,
cacheResults: true
}
}
},
{
version: "1.0.0",
domain: "claude.ai",
title: "Claude AI Interface Contract",
description: "Automation contract for Claude AI web interface",
capabilities: {
sendMessage: {
type: "action",
description: "Send a message to Claude",
selector: "[data-testid='chat-input']",
parameters: [
{
name: "message",
type: "string",
description: "Message to send to Claude",
required: true
}
]
},
getResponse: {
type: "query",
description: "Extract Claude's latest response",
selector: "[data-testid='message']:last-child",
returnType: {
type: "string",
description: "Claude's response text"
}
},
startNewConversation: {
type: "action",
description: "Start a new conversation with Claude",
selector: "[data-testid='new-chat']"
}
},
context: {
urlPatterns: [
"https://claude.ai/*"
]
}
}
];
/**
* ChatGPT Buddy Plugin - Main plugin implementation
*/
export class ChatGPTBuddyPlugin implements WebBuddyPlugin {
readonly id = 'chatgpt-buddy';
readonly name = 'ChatGPT Buddy';
readonly version = '2.0.0';
readonly description = 'AI-powered automation for ChatGPT and language models';
readonly author = 'rydnr';
readonly metadata: PluginMetadata = {
id: this.id,
name: this.name,
version: this.version,
description: this.description,
author: this.author,
license: 'MIT',
repository: 'https://github.com/rydnr/chatgpt-buddy'
};
readonly capabilities: PluginCapabilities = {
supportedDomains: [
'chat.openai.com',
'chatgpt.com',
'claude.ai',
'beta.character.ai'
],
contractDefinitions: chatGPTContracts,
permissions: [
'activeTab',
'storage',
'background',
'webRequest'
],
requiredAPIs: [
'chrome.tabs',
'chrome.storage',
'chrome.runtime',
'chrome.webRequest'
]
};
state: PluginState = 'uninitialized';
private context?: PluginContext;
private aiModelManager?: AIModelManager;
private trainingManager?: TrainingManager;
private automationEngine?: AutomationEngine;
private performanceTracker?: PerformanceTracker;
/**
* Initialize the plugin
*/
async initialize(context: PluginContext): Promise<void> {
try {
this.context = context;
this.state = 'initialized';
// Initialize core services
this.aiModelManager = new AIModelManager(context);
this.trainingManager = new TrainingManager(context);
this.automationEngine = new AutomationEngine(context);
this.performanceTracker = new PerformanceTracker(context);
// Set up event listeners
this.setupEventListeners();
// Load plugin configuration
const config = await this.loadConfiguration();
await this.applyConfiguration(config);
context.logger.info('ChatGPT Buddy Plugin initialized successfully');
} catch (error) {
this.state = 'error';
throw error;
}
}
/**
* Activate the plugin
*/
async activate(): Promise<void> {
if (!this.context) {
throw new Error('Plugin not initialized');
}
try {
this.state = 'active';
// Start core services
await this.aiModelManager?.start();
await this.trainingManager?.start();
await this.automationEngine?.start();
await this.performanceTracker?.start();
// Register contracts
for (const contract of chatGPTContracts) {
await this.context.contractRegistry.register(contract);
}
// Emit activation event
await this.context.eventBus.emit({
type: ChatGPTPluginEvents.AI_INTERACTION_REQUESTED,
source: this.id,
data: { activated: true },
timestamp: new Date().toISOString()
});
this.context.logger.info('ChatGPT Buddy Plugin activated successfully');
} catch (error) {
this.state = 'error';
throw error;
}
}
/**
* Deactivate the plugin
*/
async deactivate(): Promise<void> {
if (!this.context) {
return;
}
try {
this.state = 'inactive';
// Stop core services
await this.aiModelManager?.stop();
await this.trainingManager?.stop();
await this.automationEngine?.stop();
await this.performanceTracker?.stop();
// Unregister contracts
for (const contract of chatGPTContracts) {
await this.context.contractRegistry.unregister(contract.domain + ':' + contract.title);
}
this.context.logger.info('ChatGPT Buddy Plugin deactivated');
} catch (error) {
this.context.logger.error('Error deactivating ChatGPT Buddy Plugin', error);
throw error;
}
}
/**
* Destroy the plugin
*/
async destroy(): Promise<void> {
if (!this.context) {
return;
}
try {
this.state = 'destroyed';
// Cleanup all services
await this.aiModelManager?.destroy();
await this.trainingManager?.destroy();
await this.automationEngine?.destroy();
await this.performanceTracker?.destroy();
// Clear references
this.aiModelManager = undefined;
this.trainingManager = undefined;
this.automationEngine = undefined;
this.performanceTracker = undefined;
this.context = undefined;
} catch (error) {
console.error('Error destroying ChatGPT Buddy Plugin:', error);
throw error;
}
}
/**
* Get plugin contracts
*/
getContracts(): WebBuddyContract[] {
return [...chatGPTContracts];
}
/**
* Execute a plugin capability
*/
async executeCapability(capability: string, params: any): Promise<any> {
if (!this.context || this.state !== 'active') {
throw new Error('Plugin not active');
}
try {
switch (capability) {
case 'sendMessage':
return await this.sendMessage(params.message, params.options);
case 'getResponse':
return await this.getLatestResponse(params.options);
case 'startNewConversation':
return await this.startNewConversation();
case 'selectModel':
return await this.selectAIModel(params.model);
case 'enableTraining':
return await this.enableTrainingMode(params.options);
case 'learnPattern':
return await this.learnAutomationPattern(params.pattern);
case 'getInsights':
return await this.getAIInsights(params.options);
default:
throw new Error(`Unknown capability: ${capability}`);
}
} catch (error) {
this.context.logger.error(`Failed to execute capability: ${capability}`, error);
throw error;
}
}
/**
* Validate capability parameters
*/
async validateCapability(capability: string, params: any): Promise<{ valid: boolean; errors: string[] }> {
const errors: string[] = [];
switch (capability) {
case 'sendMessage':
if (!params.message || typeof params.message !== 'string') {
errors.push('Message parameter is required and must be a string');
}
break;
case 'selectModel':
const validModels = ['gpt-4', 'gpt-4-turbo', 'gpt-3.5-turbo', 'claude-3-opus', 'claude-3-sonnet'];
if (!params.model || !validModels.includes(params.model)) {
errors.push(`Model must be one of: ${validModels.join(', ')}`);
}
break;
default:
errors.push(`Unknown capability: ${capability}`);
}
return { valid: errors.length === 0, errors };
}
/**
* Get UI components
*/
getUIComponents(): PluginUIComponent[] {
if (!this.context) return [];
return [
this.context.createUIComponent({
type: 'overlay',
name: 'ChatGPT Training Interface',
description: 'Interactive training overlay for ChatGPT automation',
render: () => this.renderTrainingOverlay()
}),
this.context.createUIComponent({
type: 'popup',
name: 'AI Model Selector',
description: 'Select and configure AI models',
render: () => this.renderModelSelector()
}),
this.context.createUIComponent({
type: 'sidebar',
name: 'Automation Pattern Library',
description: 'Manage learned automation patterns',
render: () => this.renderPatternLibrary()
}),
this.context.createUIComponent({
type: 'panel',
name: 'AI Insights Dashboard',
description: 'View AI performance metrics and suggestions',
render: () => this.renderInsightsDashboard()
})
];
}
/**
* Get menu items
*/
getMenuItems(): PluginMenuItem[] {
if (!this.context) return [];
return [
this.context.createMenuItem({
label: 'Enable Training Mode',
description: 'Start training ChatGPT automation patterns',
icon: '🎓',
shortcut: 'Ctrl+Shift+T',
action: () => this.enableTrainingMode()
}),
this.context.createMenuItem({
label: 'Select AI Model',
description: 'Choose preferred AI model',
icon: '🤖',
action: () => this.showModelSelector()
}),
this.context.createMenuItem({
label: 'View Pattern Library',
description: 'Manage automation patterns',
icon: '📚',
action: () => this.showPatternLibrary()
}),
this.context.createMenuItem({
label: 'AI Insights',
description: 'View performance metrics',
icon: '📊',
action: () => this.showInsightsDashboard()
}),
this.context.createMenuItem({
label: 'Plugin Settings',
description: 'Configure ChatGPT Buddy settings',
icon: '⚙️',
action: () => this.showSettings()
})
];
}
/**
* Handle plugin events
*/
async onEvent(event: PluginEvent): Promise<void> {
if (!this.context) return;
try {
switch (event.type) {
case 'tab:activated':
await this.handleTabActivated(event.data);
break;
case 'automation:pattern:detected':
await this.handlePatternDetected(event.data);
break;
case 'training:session:started':
await this.handleTrainingSessionStarted(event.data);
break;
case ChatGPTPluginEvents.AI_MODEL_SWITCHED:
await this.handleModelSwitched(event.data);
break;
default:
this.context.logger.debug(`Unhandled event: ${event.type}`);
}
} catch (error) {
this.context.logger.error(`Error handling event: ${event.type}`, error);
}
}
/**
* Get default configuration
*/
getDefaultConfig(): ChatGPTPluginConfiguration {
return {
enabled: true,
settings: {
// AI Model Preferences
preferredModel: 'gpt-4',
fallbackModel: 'gpt-3.5-turbo',
// Training Settings
enableTrainingMode: true,
autoLearnPatterns: true,
trainingConfidenceThreshold: 0.8,
// Performance Settings
enablePatternRecognition: true,
enableAIInsights: true,
cacheResponses: true,
maxResponseTime: 30000,
// UI Preferences
showTrainingOverlay: true,
enableKeyboardShortcuts: true,
notificationLevel: 'normal',
// API Configuration
apiKeys: {},
rateLimits: {
requestsPerMinute: 60,
maxDailyCost: 10.0
}
},
domains: this.capabilities.supportedDomains,
permissions: this.capabilities.permissions,
uiPreferences: {
theme: 'auto',
language: 'en',
notifications: true
}
};
}
/**
* Handle configuration changes
*/
async onConfigChange(config: PluginConfiguration): Promise<void> {
if (!this.context) return;
try {
await this.applyConfiguration(config as ChatGPTPluginConfiguration);
this.context.logger.info('ChatGPT Buddy Plugin configuration updated');
} catch (error) {
this.context.logger.error('Failed to apply configuration changes', error);
throw error;
}
}
/**
* Health check
*/
async healthCheck(): Promise<{ healthy: boolean; issues: string[] }> {
const issues: string[] = [];
try {
// Check plugin state
if (this.state !== 'active') {
issues.push(`Plugin is in ${this.state} state`);
}
// Check services
if (!this.aiModelManager) {
issues.push('AI Model Manager not initialized');
}
if (!this.trainingManager) {
issues.push('Training Manager not initialized');
}
if (!this.automationEngine) {
issues.push('Automation Engine not initialized');
}
// Check context
if (!this.context) {
issues.push('Plugin context not available');
}
return { healthy: issues.length === 0, issues };
} catch (error) {
issues.push(`Health check failed: ${(error as Error).message}`);
return { healthy: false, issues };
}
}
/**
* Get plugin metrics
*/
async getMetrics(): Promise<Record<string, any>> {
const metrics: Record<string, any> = {
pluginId: this.id,
version: this.version,
state: this.state,
uptime: Date.now() - (this.metadata as any).initTime || 0
};
try {
if (this.performanceTracker) {
const perfMetrics = await this.performanceTracker.getMetrics();
metrics.performance = perfMetrics;
}
if (this.trainingManager) {
const trainingMetrics = await this.trainingManager.getMetrics();
metrics.training = trainingMetrics;
}
if (this.automationEngine) {
const automationMetrics = await this.automationEngine.getMetrics();
metrics.automation = automationMetrics;
}
} catch (error) {
metrics.error = (error as Error).message;
}
return metrics;
}
// Private helper methods
private setupEventListeners(): void {
if (!this.context) return;
// Listen for domain-specific events
this.context.eventBus.on('chatgpt:*', (event) => this.onEvent(event));
this.context.eventBus.on('automation:*', (event) => this.onEvent(event));
this.context.eventBus.on('training:*', (event) => this.onEvent(event));
}
private async loadConfiguration(): Promise<ChatGPTPluginConfiguration> {
if (!this.context) return this.getDefaultConfig();
try {
const storedConfig = await this.context.storageService.getConfig();
return { ...this.getDefaultConfig(), ...storedConfig } as ChatGPTPluginConfiguration;
} catch (error) {
this.context.logger.warn('Failed to load configuration, using defaults', error);
return this.getDefaultConfig();
}
}
private async applyConfiguration(config: ChatGPTPluginConfiguration): Promise<void> {
if (!this.context) return;
// Apply configuration to services
await this.aiModelManager?.configure(config.settings);
await this.trainingManager?.configure(config.settings);
await this.automationEngine?.configure(config.settings);
await this.performanceTracker?.configure(config.settings);
// Save configuration
await this.context.storageService.setConfig(config);
}
// Core functionality methods implementation
private async sendMessage(message: string, options?: MessageOptions): Promise<MessageResult> {
if (!this.automationEngine) {
throw new Error('Automation engine not initialized');
}
try {
const startTime = Date.now();
// Use automation engine to send message
const result = await this.automationEngine.sendMessage(message, options);
const responseTime = Date.now() - startTime;
// Record performance data
if (this.performanceTracker) {
await this.performanceTracker.recordPerformanceData({
responseTime,
accuracy: 0.9, // Default, should be measured
userSatisfaction: 0.8, // Default
cost: this.calculateMessageCost(message, options?.model),
errorOccurred: false,
requestId: this.generateRequestId(),
modelUsed: options?.model || this.aiModelManager?.getCurrentModel() || 'default',
operationType: 'sendMessage'
});
}
// Emit event
await this.context.eventBus.emit({
type: ChatGPTPluginEvents.CHATGPT_MESSAGE_SENT,
source: this.id,
data: {
message,
options,
responseTime,
success: true
},
timestamp: new Date().toISOString()
});
return {
success: true,
messageId: this.generateRequestId(),
timestamp: new Date()
};
} catch (error) {
this.context.logger.error('Failed to send message', error as Error);
// Record error
if (this.performanceTracker) {
await this.performanceTracker.recordPerformanceData({
responseTime: 0,
accuracy: 0,
userSatisfaction: 0,
errorOccurred: true,
requestId: this.generateRequestId(),
modelUsed: options?.model || 'unknown',
operationType: 'sendMessage'
});
}
throw error;
}
}
private async getLatestResponse(options?: ResponseOptions): Promise<string> {
if (!this.automationEngine) {
throw new Error('Automation engine not initialized');
}
try {
const startTime = Date.now();
// Use automation engine to extract response
const response = await this.automationEngine.extractResponse(options);
const responseTime = Date.now() - startTime;
// Emit event
await this.context.eventBus.emit({
type: ChatGPTPluginEvents.CHATGPT_RESPONSE_EXTRACTED,
source: this.id,
data: {
response,
responseTime,
length: response.length
},
timestamp: new Date().toISOString()
});
return response;
} catch (error) {
this.context.logger.error('Failed to get latest response', error as Error);
throw error;
}
}
private async startNewConversation(): Promise<void> {
if (!this.automationEngine) {
throw new Error('Automation engine not initialized');
}
try {
await this.automationEngine.startNewConversation();
// Emit event
await this.context.eventBus.emit({
type: ChatGPTPluginEvents.CONVERSATION_STARTED,
source: this.id,
data: {
timestamp: new Date().toISOString()
},
timestamp: new Date().toISOString()
});
this.context.logger.info('New conversation started successfully');
} catch (error) {
this.context.logger.error('Failed to start new conversation', error as Error);
throw error;
}
}
private async selectAIModel(model: string): Promise<void> {
if (!this.aiModelManager) {
throw new Error('AI Model Manager not initialized');
}
try {
// Switch model using AI Model Manager
await this.aiModelManager.switchToModel(model, 'user_preference');
// Use automation engine to select model in UI if available
if (this.automationEngine) {
try {
await this.automationEngine.selectModel(model);
} catch (uiError) {
this.context.logger.warn('Failed to select model in UI, but model manager updated', uiError);
}
}
this.context.logger.info(`AI model selected: ${model}`);
} catch (error) {
this.context.logger.error('Failed to select AI model', error as Error);
throw error;
}
}
private async enableTrainingMode(options?: any): Promise<void> {
if (!this.trainingManager) {
throw new Error('Training Manager not initialized');
}
try {
await this.trainingManager.enableTrainingMode();
this.context.logger.info('Training mode enabled');
} catch (error) {
this.context.logger.error('Failed to enable training mode', error as Error);
throw error;
}
}
private async learnAutomationPattern(pattern: any): Promise<void> {
if (!this.trainingManager) {
throw new Error('Training Manager not initialized');
}
try {
// Start a training session for the pattern
const sessionId = await this.trainingManager.startTrainingSession({
type: 'automation_pattern',
description: pattern.description || 'User-defined automation pattern',
expectedOutcome: pattern.expectedOutcome || 'Execute automation successfully',
context: pattern.context || {}
});
// Add the pattern as a training step
await this.trainingManager.addTrainingStep(sessionId, {
action: pattern.action,
selector: pattern.selector,
parameters: pattern.parameters,
timestamp: new Date(),
success: true
});
// Complete the session
const result = await this.trainingManager.endTrainingSession(sessionId, 'pattern_learned');
this.context.logger.info(`Automation pattern learned: ${result.patternsLearned.length} patterns created`);
} catch (error) {
this.context.logger.error('Failed to learn automation pattern', error as Error);
throw error;
}
}
private async getAIInsights(options?: any): Promise<any> {
const insights: any = {
performance: {},
recommendations: [],
trends: [],
models: {},
training: {}
};
try {
// Gather performance insights
if (this.performanceTracker) {
const performanceMetrics = await this.performanceTracker.getMetrics();
insights.performance = performanceMetrics.current;
insights.recommendations.push(...performanceMetrics.recommendations);
insights.trends = performanceMetrics.trends;
// Get optimization suggestions
const optimizations = await this.performanceTracker.getOptimizationSuggestions();
insights.recommendations.push(...optimizations.map(opt => opt.recommendation));
}
// Gather AI model insights
if (this.aiModelManager) {
const modelMetrics = await this.aiModelManager.getMetrics();
insights.models = {
current: modelMetrics.currentModel,
available: modelMetrics.availableModels,
performance: modelMetrics.modelPerformance,
switchHistory: modelMetrics.switchHistory
};
// Get model recommendations
if (options?.context) {
const recommendation = await this.aiModelManager.recommendOptimalModel(options.context);
insights.recommendations.push(`Consider switching to ${recommendation.modelId}: ${recommendation.reasoning}`);
}
}
// Gather training insights
if (this.trainingManager) {
const trainingMetrics = await this.trainingManager.getMetrics();
insights.training = {
mode: trainingMetrics.trainingMode,
patterns: trainingMetrics.learnedPatterns,
sessions: trainingMetrics.activeSessions,
recentActivity: trainingMetrics.recentActivity
};
// Get pattern recommendations
const patterns = await this.trainingManager.getLearnedPatterns();
const validPatterns = patterns.filter(p => p.confidence > 0.8);
if (validPatterns.length > 0) {
insights.recommendations.push(`${validPatterns.length} high-confidence automation patterns available`);
}
}
// Gather automation insights
if (this.automationEngine) {
const automationMetrics = await this.automationEngine.getMetrics();
insights.automation = {
activeExecutions: automationMetrics.activeExecutions,
successRate: automationMetrics.successRate,
averageExecutionTime: automationMetrics.averageExecutionTime,
recentErrors: automationMetrics.recentErrors
};
}
// Generate overall recommendations
this.generateOverallRecommendations(insights);
return insights;
} catch (error) {
this.context.logger.error('Failed to get AI insights', error as Error);
return {
error: 'Failed to gather insights',
message: (error as Error).message
};
}
}
// UI rendering methods (to be implemented)
private async renderTrainingOverlay(): Promise<HTMLElement> {
const overlay = document.createElement('div');
overlay.innerHTML = '<div>Training Overlay - Coming Soon</div>';
return overlay;
}
private async renderModelSelector(): Promise<HTMLElement> {
const selector = document.createElement('div');
selector.innerHTML = '<div>Model Selector - Coming Soon</div>';
return selector;
}
private async renderPatternLibrary(): Promise<HTMLElement> {
const library = document.createElement('div');
library.innerHTML = '<div>Pattern Library - Coming Soon</div>';
return library;
}
private async renderInsightsDashboard(): Promise<HTMLElement> {
const dashboard = document.createElement('div');
dashboard.innerHTML = '<div>AI Insights Dashboard - Coming Soon</div>';
return dashboard;
}
// Menu action methods (to be implemented)
private async showModelSelector(): Promise<void> {
// Implementation will be added in next step
}
private async showPatternLibrary(): Promise<void> {
// Implementation will be added in next step
}
private async showInsightsDashboard(): Promise<void> {
// Implementation will be added in next step
}
private async showSettings(): Promise<void> {
// Implementation will be added in next step
}
// Event handlers (to be implemented)
private async handleTabActivated(data: any): Promise<void> {
// Implementation will be added in next step
}
private async handlePatternDetected(data: any): Promise<void> {
// Implementation will be added in next step
}
private async handleTrainingSessionStarted(data: any): Promise<void> {
// Implementation will be added in next step
}
private async handleModelSwitched(data: any): Promise<void> {
this.context.logger.info('AI model switched', data);
// Record model switch for performance tracking
if (this.performanceTracker) {
await this.performanceTracker.recordPerformanceData({
responseTime: 0,
accuracy: 1,
userSatisfaction: 0.8,
cost: 0,
errorOccurred: false,
requestId: this.generateRequestId(),
modelUsed: data.currentModel,
operationType: 'model_switch'
});
}
}
// Helper methods
private calculateMessageCost(message: string, model?: string): number {
// Simplified cost calculation based on message length and model
const baseCostPerToken = 0.002; // Default cost
const estimatedTokens = Math.ceil(message.length / 4); // Rough estimation
const modelMultiplier = this.getModelCostMultiplier(model || 'gpt-3.5-turbo');
return estimatedTokens * baseCostPerToken * modelMultiplier;
}
private getModelCostMultiplier(model: string): number {
const multipliers: Record<string, number> = {
'gpt-4': 15,
'gpt-4-turbo': 7.5,
'gpt-3.5-turbo': 1,
'claude-3-opus': 18,
'claude-3-sonnet': 4
};
return multipliers[model] || 1;
}
private generateRequestId(): string {
return `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
}
private generateOverallRecommendations(insights: any): void {
// Add overall system recommendations based on all insights
if (insights.performance?.responseTime?.current > 10000) {
insights.recommendations.unshift('PRIORITY: Response time is critically high - consider model optimization');
}
if (insights.performance?.errorRate?.current > 0.1) {
insights.recommendations.unshift('PRIORITY: High error rate detected - review automation patterns');
}
if (insights.training?.patterns > 10 && insights.performance?.successRate < 0.8) {
insights.recommendations.push('Consider reviewing learned patterns for quality');
}
if (insights.models?.switchHistory?.length > 5) {
insights.recommendations.push('Frequent model switching detected - consider setting a preferred model');
}
}
}
// Service classes implementation
/**
* AI Model Manager - Handles AI model selection, switching, and optimization
*/
class AIModelManager {
private isStarted = false;
private currentModel: string;
private availableModels: AIModel[] = [];
private modelPerformance: Map<string, ModelPerformanceData> = new Map();
private modelSwitchHistory: ModelSwitchEvent[] = [];
constructor(private context: PluginContext) {
this.currentModel = 'gpt-3.5-turbo'; // Default model
this.initializeAvailableModels();
}
async start(): Promise<void> {
if (this.isStarted) return;
this.context.logger.info('Starting AI Model Manager');
// Load saved model preferences
const savedModel = await this.context.storageService.get('currentModel');
if (savedModel) {
this.currentModel = savedModel;
}
// Load performance data
const performanceData = await this.context.storageService.get('modelPerformance');
if (performanceData) {
this.modelPerformance = new Map(performanceData);
}
// Set up event listeners
this.context.eventBus.on(ChatGPTPluginEvents.AI_MODEL_SWITCHED, (event) => {
this.handleModelSwitched(event);
});
this.isStarted = true;
this.context.logger.info('AI Model Manager started successfully');
}
async stop(): Promise<void> {
if (!this.isStarted) return;
// Save current state
await this.context.storageService.set('currentModel', this.currentModel);
await this.context.storageService.set('modelPerformance', Array.from(this.modelPerformance.entries()));
this.isStarted = false;
this.context.logger.info('AI Model Manager stopped');
}
async destroy(): Promise<void> {
await this.stop();
this.modelPerformance.clear();
this.modelSwitchHistory = [];
this.context.logger.info('AI Model Manager destroyed');
}
async configure(settings: any): Promise<void> {
if (settings.preferredModel && this.isModelAvailable(settings.preferredModel)) {
await this.switchToModel(settings.preferredModel);
}
if (settings.fallbackModel) {
await this.context.storageService.set('fallbackModel', settings.fallbackModel);
}
}
async getMetrics(): Promise<any> {
return {
currentModel: this.currentModel,
availableModels: this.availableModels.length,
modelPerformance: Object.fromEntries(this.modelPerformance),
switchHistory: this.modelSwitchHistory.slice(-10), // Last 10 switches
uptime: this.isStarted ? Date.now() - (this.context as any).startTime : 0
};
}
// Public API methods
getCurrentModel(): string {
return this.currentModel;
}
getAvailableModels(): AIModel[] {
return [...this.availableModels];
}
async switchToModel(modelId: string, reason?: ModelSwitchReason): Promise<void> {
if (!this.isModelAvailable(modelId)) {
throw new Error(`Model ${modelId} is not available`);
}
const previousModel = this.currentModel;
this.currentModel = modelId;
// Record the switch
const switchEvent: ModelSwitchEvent = {
timestamp: new Date(),
fromModel: previousModel,
toModel: modelId,
reason: reason || 'user_preference',
success: true
};
this.modelSwitchHistory.push(switchEvent);
// Emit event
await this.context.eventBus.emit({
type: ChatGPTPluginEvents.AI_MODEL_SWITCHED,
source: 'ai-model-manager',
data: {
previousModel,
currentModel: modelId,
reason
},
timestamp: new Date().toISOString()
});
await this.context.storageService.set('currentModel', modelId);
this.context.logger.info(`Switched from ${previousModel} to ${modelId}`);
}
async recommendOptimalModel(context: ModelSelectionContext): Promise<ModelRecommendation> {
const recommendations: ModelRecommendation[] = [];
for (const model of this.availableModels) {
const performance = this.modelPerformance.get(model.id);
let score = model.baseScore || 0.7;
// Adjust score based on context
if (context.taskType === 'code_generation' && model.capabilities.includes('code_generation')) {
score += 0.2;
}
if (context.taskType === 'analysis' && model.capabilities.includes('analysis')) {
score += 0.15;
}
if (context.complexityLevel === 'high' && model.tier === 'premium') {
score += 0.1;
}
// Adjust based on performance history
if (performance) {
score += (performance.averageResponseTime < 5000 ? 0.1 : -0.1);
score += (performance.successRate > 0.9 ? 0.1 : -0.05);
score += (performance.userSatisfaction > 0.8 ? 0.05 : -0.05);
}
// Consider cost if specified
if (context.costPreference === 'low' && model.costTier === 'low') {
score += 0.1;
} else if (context.costPreference === 'high' && model.costTier === 'high') {
score += 0.05;
}
recommendations.push({
modelId: model.id,
confidence: Math.min(1.0, Math.max(0.1, score)),
reasoning: this.generateRecommendationReasoning(model, context, score),
estimatedPerformance: this.estimateModelPerformance(model, context)
});
}
// Sort by confidence and return the best
recommendations.sort((a, b) => b.confidence - a.confidence);
return recommendations[0];
}
async recordModelPerformance(data: ModelPerformanceRecord): Promise<void> {
const existing = this.modelPerformance.get(data.modelId) || {
modelId: data.modelId,
totalRequests: 0,
successfulRequests: 0,
totalResponseTime: 0,
averageResponseTime: 0,
successRate: 0,
totalCost: 0,
averageCost: 0,
userSatisfaction: 0,
lastUpdated: new Date()
};
// Update metrics
existing.totalRequests++;
if (data.success) existing.successfulRequests++;
existing.totalResponseTime += data.responseTime;
existing.averageResponseTime = existing.totalResponseTime / existing.totalRequests;
existing.successRate = existing.successfulRequests / existing.totalRequests;
existing.totalCost += data.cost || 0;
existing.averageCost = existing.totalCost / existing.totalRequests;
// Update user satisfaction (weighted average)
if (data.userSatisfaction !== undefined) {
existing.userSatisfaction = (existing.userSatisfaction * 0.8) + (data.userSatisfaction * 0.2);
}
existing.lastUpdated = new Date();
this.modelPerformance.set(data.modelId, existing);
// Persist to storage periodically
if (existing.totalRequests % 10 === 0) {
await this.context.storageService.set('modelPerformance', Array.from(this.modelPerformance.entries()));
}
}
// Private helper methods
private initializeAvailableModels(): void {
this.availableModels = [
{
id: 'gpt-4',
name: 'GPT-4',
provider: 'openai',
tier: 'premium',
costTier: 'high',
capabilities: ['text_generation', 'code_generation', 'analysis', 'reasoning'],
maxTokens: 8192,
baseScore: 0.9,
description: 'Most capable model for complex tasks'
},
{
id: 'gpt-4-turbo',
name: 'GPT-4 Turbo',
provider: 'openai',
tier: 'premium',
costTier: 'medium',
capabilities: ['text_generation', 'code_generation', 'analysis', 'reasoning', 'vision'],
maxTokens: 128000,
baseScore: 0.85,
description: 'Fast and efficient GPT-4 variant'
},
{
id: 'gpt-3.5-turbo',
name: 'GPT-3.5 Turbo',
provider: 'openai',
tier: 'standard',
costTier: 'low',
capabilities: ['text_generation', 'basic_analysis', 'conversation'],
maxTokens: 4096,
baseScore: 0.7,
description: 'Balanced performance and cost'
},
{
id: 'claude-3-opus',
name: 'Claude 3 Opus',
provider: 'anthropic',
tier: 'premium',
costTier: 'high',
capabilities: ['text_generation', 'analysis', 'reasoning', 'safety'],
maxTokens: 200000,
baseScore: 0.88,
description: 'Excellent for complex analysis and safety'
},
{
id: 'claude-3-sonnet',
name: 'Claude 3 Sonnet',
provider: 'anthropic',
tier: 'standard',
costTier: 'medium',
capabilities: ['text_generation', 'analysis', 'reasoning'],
maxTokens: 200000,
baseScore: 0.75,
description: 'Balanced Claude model for most tasks'
}
];
}
private isModelAvailable(modelId: string): boolean {
return this.availableModels.some(model => model.id === modelId);
}
private async handleModelSwitched(event: PluginEvent): Promise<void> {
// Handle model switch events for analytics and optimization
this.context.logger.debug('Model switch event received', event.data);
}
private generateRecommendationReasoning(model: AIModel, context: ModelSelectionContext, score: number): string {
const reasons = [];
if (model.capabilities.includes(context.taskType)) {
reasons.push(`Optimized for ${context.taskType}`);
}
if (context.complexityLevel === 'high' && model.tier === 'premium') {
reasons.push('Premium model suitable for complex tasks');
}
if (context.costPreference === 'low' && model.costTier === 'low') {
reasons.push('Cost-effective option');
}
const performance = this.modelPerformance.get(model.id);
if (performance?.successRate > 0.9) {
reasons.push('High success rate in previous tasks');
}
return reasons.join('; ');
}
private estimateModelPerformance(model: AIModel, context: ModelSelectionContext): EstimatedPerformance {
const historical = this.modelPerformance.get(model.id);
return {
responseTime: historical?.averageResponseTime || this.getBaselineResponseTime(model),
successRate: historical?.successRate || 0.85,
cost: historical?.averageCost || this.getBaselineCost(model),
quality: this.estimateQuality(model, context)
};
}
private getBaselineResponseTime(model: AIModel): number {
const baselines: Record<string, number> = {
'gpt-4': 8000,
'gpt-4-turbo': 4000,
'gpt-3.5-turbo': 2000,
'claude-3-opus': 6000,
'claude-3-sonnet': 3000
};
return baselines[model.id] || 5000;
}
private getBaselineCost(model: AIModel): number {
const baselines: Record<string, number> = {
'gpt-4': 0.06,
'gpt-4-turbo': 0.03,
'gpt-3.5-turbo': 0.002,
'claude-3-opus': 0.075,
'claude-3-sonnet': 0.015
};
return baselines[model.id] || 0.01;
}
private estimateQuality(model: AIModel, context: ModelSelectionContext): number {
let quality = model.baseScore || 0.7;
if (model.capabilities.includes(context.taskType)) {
quality += 0.1;
}
if (context.complexityLevel === 'high' && model.tier === 'premium') {
quality += 0.05;
}
return Math.min(1.0, quality);
}
}
/**
* Training Manager - Handles automation pattern training and learning
*/
class TrainingManager {
private isStarted = false;
private trainingMode = false;
private activeSessions: Map<string, TrainingSession> = new Map();
private learnedPatterns: Map<string, LearnedPattern> = new Map();
private trainingHistory: TrainingRecord[] = [];
private confidence: number = 0.8;
constructor(private context: PluginContext) {}
async start(): Promise<void> {
if (this.isStarted) return;
this.context.logger.info('Starting Training Manager');
// Load existing patterns
const patterns = await this.context.storageService.get('learnedPatterns');
if (patterns) {
this.learnedPatterns = new Map(patterns);
}
// Load training history
const history = await this.context.storageService.get('trainingHistory');
if (history) {
this.trainingHistory = history;
}
// Set up event listeners
this.context.eventBus.on(ChatGPTPluginEvents.TRAINING_MODE_ENABLED, (event) => {
this.handleTrainingModeEnabled(event);
});
this.context.eventBus.on(ChatGPTPluginEvents.TRAINING_PATTERN_LEARNED, (event) => {
this.handlePatternLearned(event);
});
this.isStarted = true;
this.context.logger.info('Training Manager started successfully');
}
async stop(): Promise<void> {
if (!this.isStarted) return;
// Save current state
await this.context.storageService.set('learnedPatterns', Array.from(this.learnedPatterns.entries()));
await this.context.storageService.set('trainingHistory', this.trainingHistory);
// End all active sessions
for (const session of this.activeSessions.values()) {
await this.endTrainingSession(session.id, 'manager_stopped');
}
this.isStarted = false;
this.context.logger.info('Training Manager stopped');
}
async destroy(): Promise<void> {
await this.stop();
this.activeSessions.clear();
this.learnedPatterns.clear();
this.trainingHistory = [];
this.context.logger.info('Training Manager destroyed');
}
async configure(settings: any): Promise<void> {
if (settings.enableTrainingMode !== undefined) {
this.trainingMode = settings.enableTrainingMode;
}
if (settings.trainingConfidenceThreshold !== undefined) {
this.confidence = settings.trainingConfidenceThreshold;
}
if (settings.autoLearnPatterns !== undefined) {
await this.context.storageService.set('autoLearnPatterns', settings.autoLearnPatterns);
}
}
async getMetrics(): Promise<any> {
return {
trainingMode: this.trainingMode,
activeSessions: this.activeSessions.size,
learnedPatterns: this.learnedPatterns.size,
trainingHistory: this.trainingHistory.length,
confidenceThreshold: this.confidence,
recentActivity: this.trainingHistory.slice(-10)
};
}
// Public API methods
async enableTrainingMode(): Promise<void> {
this.trainingMode = true;
await this.context.eventBus.emit({
type: ChatGPTPluginEvents.TRAINING_MODE_ENABLED,
source: 'training-manager',
data: { enabled: true },
timestamp: new Date().toISOString()
});
this.context.logger.info('Training mode enabled');
}
async disableTrainingMode(): Promise<void> {
this.trainingMode = false;
// End all active sessions
for (const session of this.activeSessions.values()) {
await this.endTrainingSession(session.id, 'training_disabled');
}
this.context.logger.info('Training mode disabled');
}
async startTrainingSession(request: TrainingRequest): Promise<string> {
if (!this.trainingMode) {
throw new Error('Training mode is not enabled');
}
const sessionId = this.generateSessionId();
const session: TrainingSession = {
id: sessionId,
startTime: new Date(),
request,
status: 'active',
steps: [],
patterns: [],
confidence: 0
};
this.activeSessions.set(sessionId, session);
this.context.logger.info(`Started training session: ${sessionId}`);
return sessionId;
}
async addTrainingStep(sessionId: string, step: TrainingStep): Promise<void> {
const session = this.activeSessions.get(sessionId);
if (!session) {
throw new Error(`Training session ${sessionId} not found`);
}
session.steps.push(step);
// Analyze patterns after each step
await this.analyzeStepForPatterns(session, step);
this.context.logger.debug(`Added training step to session ${sessionId}`, step);
}
async endTrainingSession(sessionId: string, reason: string): Promise<TrainingResult> {
const session = this.activeSessions.get(sessionId);
if (!session) {
throw new Error(`Training session ${sessionId} not found`);
}
session.endTime = new Date();
session.status = 'completed';
// Generate final patterns
const finalPatterns = await this.generatePatternsFromSession(session);
// Store learned patterns
for (const pattern of finalPatterns) {
if (pattern.confidence >= this.confidence) {
await this.storeLearnedPattern(pattern);
}
}
// Create training record
const record: TrainingRecord = {
sessionId,
startTime: session.startTime,
endTime: session.endTime!,
request: session.