Просмотр исходного кода

Merge remote-tracking branch 'origin/master' into imprv/context-for-editor-assistant

Yuki Takei 9 месяцев назад
Родитель
Сommit
a181ebd9f0

+ 35 - 167
apps/app/src/features/openai/client/services/client-engine-integration.tsx

@@ -4,12 +4,11 @@
  */
  */
 
 
 import {
 import {
-  useCallback, useRef, useState, useMemo,
+  useCallback, useRef, useMemo,
 } from 'react';
 } from 'react';
 
 
 import type { Text as YText } from 'yjs';
 import type { Text as YText } from 'yjs';
 
 
-import type { LlmEditorAssistantDiff } from '../../interfaces/editor-assistant/llm-response-schemas';
 import type { SseDetectedDiff } from '../../interfaces/editor-assistant/sse-schemas';
 import type { SseDetectedDiff } from '../../interfaces/editor-assistant/sse-schemas';
 import type { ProcessingResult } from '../../interfaces/editor-assistant/types';
 import type { ProcessingResult } from '../../interfaces/editor-assistant/types';
 
 
@@ -61,30 +60,12 @@ export interface ProcessingProgress {
 // -----------------------------------------------------------------------------
 // -----------------------------------------------------------------------------
 
 
 export function useClientEngineIntegration(config: Partial<ClientEngineConfig> = {}): {
 export function useClientEngineIntegration(config: Partial<ClientEngineConfig> = {}): {
-  processDetectedDiffsClient: (
-    content: string,
-    detectedDiffs: SseDetectedDiff[],
-  ) => Promise<ProcessingResult>;
-  applyToYText: (yText: YText, processedContent: string) => boolean;
   processHybrid: (
   processHybrid: (
     content: string,
     content: string,
     detectedDiffs: SseDetectedDiff[],
     detectedDiffs: SseDetectedDiff[],
     serverProcessingFn: () => Promise<void>,
     serverProcessingFn: () => Promise<void>,
   ) => Promise<{ success: boolean; method: 'client' | 'server'; result?: ProcessingResult }>;
   ) => Promise<{ success: boolean; method: 'client' | 'server'; result?: ProcessingResult }>;
-  isClientProcessing: boolean;
-  lastProcessingMethod: 'client' | 'server' | 'hybrid';
-  processingMetrics: ProcessingMetrics[];
-  getPerformanceComparison: () => {
-    clientAvgTime: number;
-    serverAvgTime: number;
-    timeImprovement: number;
-    clientSuccessRate: number;
-    serverSuccessRate: number;
-    totalClientProcessing: number;
-    totalServerProcessing: number;
-  } | null;
-  resetMetrics: () => void;
-  config: ClientEngineConfig;
+  applyToYText: (yText: YText, processedContent: string) => boolean;
   isClientProcessingEnabled: boolean;
   isClientProcessingEnabled: boolean;
 } {
 } {
   // Configuration with defaults
   // Configuration with defaults
@@ -97,11 +78,6 @@ export function useClientEngineIntegration(config: Partial<ClientEngineConfig> =
     ...config,
     ...config,
   }), [config]);
   }), [config]);
 
 
-  // State
-  const [isClientProcessing, setIsClientProcessing] = useState(false);
-  const [processingMetrics, setProcessingMetrics] = useState<ProcessingMetrics[]>([]);
-  const [lastProcessingMethod, setLastProcessingMethod] = useState<'client' | 'server' | 'hybrid'>('server');
-
   // Client processor instance
   // Client processor instance
   const clientProcessor = useRef<ClientSearchReplaceProcessor>();
   const clientProcessor = useRef<ClientSearchReplaceProcessor>();
 
 
@@ -114,82 +90,6 @@ export function useClientEngineIntegration(config: Partial<ClientEngineConfig> =
     });
     });
   }
   }
 
 
-  /**
-   * Process detected diffs using client-side engine
-   */
-  const processDetectedDiffsClient = useCallback(async(
-      content: string,
-      detectedDiffs: SseDetectedDiff[],
-  ): Promise<ProcessingResult> => {
-    if (!clientProcessor.current) {
-      throw new Error('Client processor not initialized');
-    }
-
-    const startTime = performance.now();
-    setIsClientProcessing(true);
-
-    try {
-      // Convert SseDetectedDiff to LlmEditorAssistantDiff format
-      const diffs: LlmEditorAssistantDiff[] = detectedDiffs
-        .map(d => d.diff)
-        .filter((diff): diff is LlmEditorAssistantDiff => diff != null);
-
-      // Validate required fields for client processing
-      for (const diff of diffs) {
-        if (!diff.startLine) {
-          throw new Error(
-            `startLine is required for client processing but missing in diff: ${diff.search?.substring(0, 50)}...`,
-          );
-        }
-        if (!diff.search) {
-          throw new Error(
-            `search field is required for client processing but missing in diff at line ${diff.startLine}`,
-          );
-        }
-      }
-
-      // Process with client engine
-      const diffResult = await clientProcessor.current.processMultipleDiffs(content, diffs, {
-        enableProgressCallbacks: true,
-        batchSize: finalConfig.batchSize,
-        maxProcessingTime: finalConfig.maxProcessingTime,
-      });
-
-      // Convert DiffApplicationResult to ProcessingResult
-      const processingTime = performance.now() - startTime;
-      const result: ProcessingResult = {
-        success: diffResult.success,
-        error: diffResult.failedParts?.[0],
-        matches: [], // Client engine doesn't expose individual matches
-        appliedCount: diffResult.appliedCount,
-        skippedCount: Math.max(0, diffs.length - diffResult.appliedCount),
-        modifiedText: diffResult.content || content,
-        originalText: content,
-        processingTime,
-      };
-
-      // Record metrics
-      const metrics: ProcessingMetrics = {
-        method: 'client',
-        processingTime,
-        diffsCount: diffs.length,
-        appliedCount: result.appliedCount,
-        successRate: diffs.length > 0 ? (result.appliedCount / diffs.length) * 100 : 100,
-        error: result.success ? undefined : result.error?.message,
-      };
-
-      if (finalConfig.enablePerformanceMetrics) {
-        setProcessingMetrics(prev => [...prev, metrics]);
-      }
-
-      setLastProcessingMethod('client');
-      return result;
-    }
-    finally {
-      setIsClientProcessing(false);
-    }
-  }, [finalConfig]);
-
   /**
   /**
    * Apply processed content to YText (CodeMirror integration)
    * Apply processed content to YText (CodeMirror integration)
    */
    */
@@ -228,26 +128,52 @@ export function useClientEngineIntegration(config: Partial<ClientEngineConfig> =
       detectedDiffs: SseDetectedDiff[],
       detectedDiffs: SseDetectedDiff[],
       serverProcessingFn: () => Promise<void>,
       serverProcessingFn: () => Promise<void>,
   ): Promise<{ success: boolean; method: 'client' | 'server'; result?: ProcessingResult }> => {
   ): Promise<{ success: boolean; method: 'client' | 'server'; result?: ProcessingResult }> => {
-    if (!finalConfig.enableClientProcessing) {
+    if (!finalConfig.enableClientProcessing || !clientProcessor.current) {
       // Client processing disabled, use server only
       // Client processing disabled, use server only
       await serverProcessingFn();
       await serverProcessingFn();
-      setLastProcessingMethod('server');
       return { success: true, method: 'server' };
       return { success: true, method: 'server' };
     }
     }
 
 
     try {
     try {
-      // Try client processing first
-      const result = await processDetectedDiffsClient(content, detectedDiffs);
+      // Convert SseDetectedDiff to LlmEditorAssistantDiff format
+      const diffs = detectedDiffs
+        .map(d => d.diff)
+        .filter((diff): diff is NonNullable<typeof diff> => diff != null);
+
+      // Validate required fields for client processing
+      for (const diff of diffs) {
+        if (!diff.startLine || !diff.search) {
+          throw new Error('Missing required fields for client processing');
+        }
+      }
+
+      // Process with client engine
+      const diffResult = await clientProcessor.current.processMultipleDiffs(content, diffs, {
+        enableProgressCallbacks: true,
+        batchSize: finalConfig.batchSize,
+        maxProcessingTime: finalConfig.maxProcessingTime,
+      });
+
+      // Convert DiffApplicationResult to ProcessingResult
+      const processingTime = performance.now();
+      const result: ProcessingResult = {
+        success: diffResult.success,
+        error: diffResult.failedParts?.[0],
+        matches: [],
+        appliedCount: diffResult.appliedCount,
+        skippedCount: Math.max(0, diffs.length - diffResult.appliedCount),
+        modifiedText: diffResult.content || content,
+        originalText: content,
+        processingTime,
+      };
 
 
       if (result.success) {
       if (result.success) {
-        setLastProcessingMethod('client');
         return { success: true, method: 'client', result };
         return { success: true, method: 'client', result };
       }
       }
 
 
       // Client processing failed, fallback to server if enabled
       // Client processing failed, fallback to server if enabled
       if (finalConfig.enableServerFallback) {
       if (finalConfig.enableServerFallback) {
         await serverProcessingFn();
         await serverProcessingFn();
-        setLastProcessingMethod('server');
         return { success: true, method: 'server' };
         return { success: true, method: 'server' };
       }
       }
 
 
@@ -258,65 +184,19 @@ export function useClientEngineIntegration(config: Partial<ClientEngineConfig> =
       // Fallback to server on error
       // Fallback to server on error
       if (finalConfig.enableServerFallback) {
       if (finalConfig.enableServerFallback) {
         await serverProcessingFn();
         await serverProcessingFn();
-        setLastProcessingMethod('server');
         return { success: true, method: 'server' };
         return { success: true, method: 'server' };
       }
       }
 
 
       return { success: false, method: 'client' };
       return { success: false, method: 'client' };
     }
     }
-  }, [finalConfig, processDetectedDiffsClient]);
-
-  /**
-   * Get performance comparison between client and server processing
-   */
-  const getPerformanceComparison = useCallback(() => {
-    const clientMetrics = processingMetrics.filter(m => m.method === 'client');
-    const serverMetrics = processingMetrics.filter(m => m.method === 'server');
-
-    if (clientMetrics.length === 0 || serverMetrics.length === 0) {
-      return null;
-    }
-
-    const avgClientTime = clientMetrics.reduce((sum, m) => sum + m.processingTime, 0) / clientMetrics.length;
-    const avgServerTime = serverMetrics.reduce((sum, m) => sum + m.processingTime, 0) / serverMetrics.length;
-    const avgClientSuccess = clientMetrics.reduce((sum, m) => sum + m.successRate, 0) / clientMetrics.length;
-    const avgServerSuccess = serverMetrics.reduce((sum, m) => sum + m.successRate, 0) / serverMetrics.length;
-
-    return {
-      clientAvgTime: avgClientTime,
-      serverAvgTime: avgServerTime,
-      timeImprovement: ((avgServerTime - avgClientTime) / avgServerTime) * 100,
-      clientSuccessRate: avgClientSuccess,
-      serverSuccessRate: avgServerSuccess,
-      totalClientProcessing: clientMetrics.length,
-      totalServerProcessing: serverMetrics.length,
-    };
-  }, [processingMetrics]);
-
-  /**
-   * Reset metrics for new comparison
-   */
-  const resetMetrics = useCallback(() => {
-    setProcessingMetrics([]);
-  }, []);
+  }, [finalConfig]);
 
 
   return {
   return {
     // Processing functions
     // Processing functions
-    processDetectedDiffsClient,
     applyToYText,
     applyToYText,
     processHybrid,
     processHybrid,
 
 
-    // State
-    isClientProcessing,
-    lastProcessingMethod,
-    processingMetrics,
-
-    // Metrics and comparison
-    getPerformanceComparison,
-    resetMetrics,
-
     // Configuration
     // Configuration
-    config: finalConfig,
     isClientProcessingEnabled: finalConfig.enableClientProcessing,
     isClientProcessingEnabled: finalConfig.enableClientProcessing,
   };
   };
 }
 }
@@ -325,18 +205,6 @@ export function useClientEngineIntegration(config: Partial<ClientEngineConfig> =
 // Utility Functions
 // Utility Functions
 // -----------------------------------------------------------------------------
 // -----------------------------------------------------------------------------
 
 
-/**
- * Convert SseDetectedDiff to content string for processing
- */
-export function extractContentFromDetectedDiffs(detectedDiffs: SseDetectedDiff[]): string {
-  // This would need to be implemented based on how the current system
-  // extracts content from detected diffs
-  return detectedDiffs
-    .map(d => d.diff?.search || '')
-    .filter(Boolean)
-    .join('\n');
-}
-
 /**
 /**
  * Feature flag for enabling client processing
  * Feature flag for enabling client processing
  */
  */

+ 0 - 173
apps/app/src/features/openai/client/services/editor-assistant/diff-application.ts

@@ -128,52 +128,6 @@ export class ClientDiffApplicationEngine {
     }
     }
   }
   }
 
 
-  /**
-   * Apply diff directly to an editor adapter with real-time integration
-   */
-  async applyDiffToEditor(
-      editor: EditorAdapter,
-      diff: LlmEditorAssistantDiff,
-      options: {
-      createCheckpoint?: boolean;
-      preserveSelection?: boolean;
-    } = {},
-  ): Promise<SingleDiffResult> {
-    const { createCheckpoint = true } = options;
-
-    try {
-      // Create undo checkpoint for easy reversal
-      if (createCheckpoint) {
-        editor.createUndoCheckpoint();
-      }
-
-      // Get current content
-      const currentContent = editor.getContent();
-
-      // Apply diff to content
-      const result = this.applySingleDiff(currentContent, diff);
-
-      if (!result.success || !result.updatedLines) {
-        return result;
-      }
-
-      // Apply changes to editor
-      const newContent = result.updatedLines.join('\n');
-      editor.setContent(newContent);
-
-      return result;
-
-    }
-    catch (error) {
-      return {
-        success: false,
-        error: this.errorHandler.createContentError(
-          error as Error,
-          'Editor integration error',
-        ),
-      };
-    }
-  }
 
 
   /**
   /**
    * Apply multiple diffs in sequence with proper delta tracking
    * Apply multiple diffs in sequence with proper delta tracking
@@ -332,13 +286,6 @@ export class ClientDiffApplicationEngine {
     this.fuzzyMatcher.setThreshold(this.config.fuzzyThreshold);
     this.fuzzyMatcher.setThreshold(this.config.fuzzyThreshold);
   }
   }
 
 
-  /**
-   * Get current configuration
-   */
-  getConfig(): Required<ProcessorConfig> {
-    return { ...this.config };
-  }
-
   /**
   /**
    * Validate diff before application
    * Validate diff before application
    */
    */
@@ -370,124 +317,4 @@ export class ClientDiffApplicationEngine {
     };
     };
   }
   }
 
 
-  /**
-   * Preview diff application without making changes
-   */
-  previewDiff(
-      content: string,
-      diff: LlmEditorAssistantDiff,
-  ): {
-    preview: string;
-    success: boolean;
-    changes: {
-      added: number;
-      removed: number;
-      modified: number;
-    };
-  } {
-    const result = this.applySingleDiff(content, diff);
-
-    if (!result.success || !result.updatedLines) {
-      return {
-        preview: content,
-        success: false,
-        changes: { added: 0, removed: 0, modified: 0 },
-      };
-    }
-
-    const newLines = result.updatedLines;
-
-    return {
-      preview: newLines.join('\n'),
-      success: true,
-      changes: {
-        added: Math.max(0, result.lineDelta || 0),
-        removed: Math.max(0, -(result.lineDelta || 0)),
-        modified: 1, // At least one diff was applied
-      },
-    };
-  }
-
 }
 }
-
-// -----------------------------------------------------------------------------
-// Browser-Specific Editor Adapters
-// -----------------------------------------------------------------------------
-
-/**
- * Simple textarea adapter for basic text inputs
- */
-export class TextAreaAdapter implements EditorAdapter {
-
-  // eslint-disable-next-line no-useless-constructor
-  constructor(private textarea: HTMLTextAreaElement) {}
-
-  getContent(): string {
-    return this.textarea.value;
-  }
-
-  setContent(content: string): void {
-    this.textarea.value = content;
-  }
-
-  replaceRange(startLine: number, endLine: number, newText: string): void {
-    const lines = this.getContent().split('\n');
-    const newLines = [
-      ...lines.slice(0, startLine),
-      newText,
-      ...lines.slice(endLine + 1),
-    ];
-    this.setContent(newLines.join('\n'));
-  }
-
-  getLineCount(): number {
-    return this.getContent().split('\n').length;
-  }
-
-  getLine(lineNumber: number): string {
-    const lines = this.getContent().split('\n');
-    return lines[lineNumber] || '';
-  }
-
-  insertText(line: number, column: number, text: string): void {
-    // Basic implementation for textarea
-    const lines = this.getContent().split('\n');
-    const targetLine = lines[line] || '';
-    lines[line] = targetLine.slice(0, column) + text + targetLine.slice(column);
-    this.setContent(lines.join('\n'));
-  }
-
-  deleteRange(startLine: number, startCol: number, endLine: number, endCol: number): void {
-    const lines = this.getContent().split('\n');
-
-    if (startLine === endLine) {
-      // Same line deletion
-      const line = lines[startLine] || '';
-      lines[startLine] = line.slice(0, startCol) + line.slice(endCol);
-    }
-    else {
-      // Multi-line deletion
-      const startLineContent = lines[startLine]?.slice(0, startCol) || '';
-      const endLineContent = lines[endLine]?.slice(endCol) || '';
-      lines.splice(startLine, endLine - startLine + 1, startLineContent + endLineContent);
-    }
-
-    this.setContent(lines.join('\n'));
-  }
-
-  createUndoCheckpoint(): void {
-    // Textarea doesn't have built-in undo checkpoints
-    // This would need to be implemented with a custom history system
-  }
-
-}
-
-// -----------------------------------------------------------------------------
-// Export Default Instance
-// -----------------------------------------------------------------------------
-
-/**
- * Default client diff application engine
- * Pre-configured for typical browser usage
- */
-export const defaultClientDiffEngine = new ClientDiffApplicationEngine();

+ 0 - 187
apps/app/src/features/openai/client/services/editor-assistant/error-handling.ts

@@ -12,12 +12,9 @@ import type { DiffError, MatchResult } from '../../../interfaces/editor-assistan
 
 
 export const CLIENT_ERROR_MESSAGES = {
 export const CLIENT_ERROR_MESSAGES = {
   SEARCH_NOT_FOUND: 'Search content not found in the document',
   SEARCH_NOT_FOUND: 'Search content not found in the document',
-  SIMILARITY_TOO_LOW: 'Search content is too different from the closest match',
-  MULTIPLE_MATCHES: 'Multiple similar matches found - search is ambiguous',
   EMPTY_SEARCH: 'Search content cannot be empty',
   EMPTY_SEARCH: 'Search content cannot be empty',
   CONTENT_ERROR: 'Invalid or corrupted content',
   CONTENT_ERROR: 'Invalid or corrupted content',
   TIMEOUT_ERROR: 'Search operation timed out',
   TIMEOUT_ERROR: 'Search operation timed out',
-  BROWSER_ERROR: 'Browser compatibility issue detected',
 } as const;
 } as const;
 
 
 export const CLIENT_SUGGESTIONS = {
 export const CLIENT_SUGGESTIONS = {
@@ -27,18 +24,6 @@ export const CLIENT_SUGGESTIONS = {
     'Verify line endings match your content',
     'Verify line endings match your content',
     'Use the browser\'s search function to locate content first',
     'Use the browser\'s search function to locate content first',
   ],
   ],
-  SIMILARITY_TOO_LOW: [
-    'Increase the similarity threshold in settings',
-    'Use a more exact search pattern',
-    'Check for typos or formatting differences',
-    'Try searching for a unique phrase within the target',
-  ],
-  MULTIPLE_MATCHES: [
-    'Add more context to make the search unique',
-    'Include surrounding lines in your search',
-    'Use line numbers to specify the exact location',
-    'Search for a more specific pattern',
-  ],
   EMPTY_SEARCH: [
   EMPTY_SEARCH: [
     'Provide valid search content',
     'Provide valid search content',
     'Check that your diff contains the search text',
     'Check that your diff contains the search text',
@@ -53,11 +38,6 @@ export const CLIENT_SUGGESTIONS = {
     'Reduce the document size if possible',
     'Reduce the document size if possible',
     'Check browser performance and memory usage',
     'Check browser performance and memory usage',
   ],
   ],
-  BROWSER_ERROR: [
-    'Update to a modern browser version',
-    'Check browser compatibility settings',
-    'Try disabling browser extensions temporarily',
-  ],
 } as const;
 } as const;
 
 
 // -----------------------------------------------------------------------------
 // -----------------------------------------------------------------------------
@@ -105,67 +85,6 @@ export class ClientErrorHandler {
     return error;
     return error;
   }
   }
 
 
-  /**
-   * Create a detailed error for similarity too low
-   */
-  createSimilarityTooLowError(
-      searchContent: string,
-      bestMatch: string,
-      similarity: number,
-      threshold: number,
-      startLine?: number,
-  ): DiffError {
-    const error: DiffError = {
-      type: 'SIMILARITY_TOO_LOW',
-      message: `${CLIENT_ERROR_MESSAGES.SIMILARITY_TOO_LOW} (${Math.floor(similarity * 100)}% < ${Math.floor(threshold * 100)}%)`,
-      line: startLine,
-      details: {
-        searchContent,
-        bestMatch,
-        similarity,
-        suggestions: [
-          `Current similarity: ${Math.floor(similarity * 100)}%, required: ${Math.floor(threshold * 100)}%`,
-          ...CLIENT_SUGGESTIONS.SIMILARITY_TOO_LOW,
-        ],
-        correctFormat: this.generateCorrectFormat(searchContent, bestMatch),
-      },
-    };
-
-    this.logError(error, 'Similarity too low');
-    return error;
-  }
-
-  /**
-   * Create a detailed error for multiple matches
-   */
-  createMultipleMatchesError(
-      searchContent: string,
-      matches: MatchResult[],
-      startLine?: number,
-  ): DiffError {
-    const matchInfo = matches
-      .slice(0, 3) // Show only first 3 matches
-      .map((match, index) => `Match ${index + 1}: line ${match.index ? match.index + 1 : 'unknown'} (${Math.floor((match.similarity || 0) * 100)}%)`)
-      .join(', ');
-
-    const error: DiffError = {
-      type: 'MULTIPLE_MATCHES',
-      message: `${CLIENT_ERROR_MESSAGES.MULTIPLE_MATCHES}: ${matchInfo}`,
-      line: startLine,
-      details: {
-        searchContent,
-        suggestions: [
-          `Found ${matches.length} similar matches`,
-          ...CLIENT_SUGGESTIONS.MULTIPLE_MATCHES,
-        ],
-        lineRange: `Multiple locations: ${matchInfo}`,
-      },
-    };
-
-    this.logError(error, 'Multiple matches found');
-    return error;
-  }
-
   /**
   /**
    * Create an error for empty search content
    * Create an error for empty search content
    */
    */
@@ -229,29 +148,6 @@ export class ClientErrorHandler {
     return error;
     return error;
   }
   }
 
 
-  /**
-   * Create an error for browser compatibility issues
-   */
-  createBrowserError(
-      feature: string,
-      fallbackAvailable = false,
-  ): DiffError {
-    const error: DiffError = {
-      type: 'CONTENT_ERROR',
-      message: `${CLIENT_ERROR_MESSAGES.BROWSER_ERROR}: ${feature} not supported`,
-      details: {
-        searchContent: `Browser feature: ${feature}`,
-        suggestions: [
-          fallbackAvailable ? 'Using fallback implementation' : 'No fallback available',
-          ...CLIENT_SUGGESTIONS.BROWSER_ERROR,
-        ],
-      },
-    };
-
-    this.logError(error, 'Browser compatibility issue');
-    return error;
-  }
-
   // -----------------------------------------------------------------------------
   // -----------------------------------------------------------------------------
   // Utility Methods
   // Utility Methods
   // -----------------------------------------------------------------------------
   // -----------------------------------------------------------------------------
@@ -334,87 +230,4 @@ export class ClientErrorHandler {
     return summary + errorList + moreErrors;
     return summary + errorList + moreErrors;
   }
   }
 
 
-  // -----------------------------------------------------------------------------
-  // Configuration Methods
-  // -----------------------------------------------------------------------------
-
-  /**
-   * Check if console logging is enabled
-   */
-  isConsoleLoggingEnabled(): boolean {
-    return this.enableConsoleLogging;
-  }
-
-  /**
-   * Check if user feedback is enabled
-   */
-  isUserFeedbackEnabled(): boolean {
-    return this.enableUserFeedback;
-  }
-
 }
 }
-
-// -----------------------------------------------------------------------------
-// Utility Functions
-// -----------------------------------------------------------------------------
-
-/**
- * Quick error creation for common scenarios
- */
-export function createQuickError(
-    type: keyof typeof CLIENT_ERROR_MESSAGES,
-    searchContent: string,
-    additionalInfo?: string,
-): DiffError {
-  return {
-    type: type as DiffError['type'],
-    message: CLIENT_ERROR_MESSAGES[type] + (additionalInfo ? `: ${additionalInfo}` : ''),
-    details: {
-      searchContent,
-      suggestions: [...(CLIENT_SUGGESTIONS[type] || ['Contact support for assistance'])],
-    },
-  };
-}
-
-/**
- * Validate browser support for required features
- */
-export function validateBrowserSupport(): {
-  supported: boolean;
-  missing: string[];
-  warnings: string[];
-  } {
-  const missing: string[] = [];
-  const warnings: string[] = [];
-
-  // Check for required APIs
-  if (typeof performance === 'undefined' || typeof performance.now !== 'function') {
-    missing.push('Performance API');
-  }
-
-  if (typeof String.prototype.normalize !== 'function') {
-    missing.push('Unicode normalization');
-  }
-
-  // Check for optional but recommended features
-  // eslint-disable-next-line no-console
-  if (typeof console === 'undefined' || typeof console.warn !== 'function') {
-    warnings.push('Console API limited');
-  }
-
-  return {
-    supported: missing.length === 0,
-    missing,
-    warnings,
-  };
-}
-
-// -----------------------------------------------------------------------------
-// Export Default Instance
-// -----------------------------------------------------------------------------
-
-/**
- * Default client error handler instance
- * Pre-configured for typical browser usage
- */
-export const defaultClientErrorHandler = new ClientErrorHandler(true, true);

+ 7 - 388
apps/app/src/features/openai/interfaces/editor-assistant/sse-schemas.spec.ts

@@ -2,7 +2,6 @@ import {
   SseMessageSchema,
   SseMessageSchema,
   SseDetectedDiffSchema,
   SseDetectedDiffSchema,
   SseFinalizedSchema,
   SseFinalizedSchema,
-  hasApplicationResult,
   type SseMessage,
   type SseMessage,
   type SseDetectedDiff,
   type SseDetectedDiff,
   type SseFinalized,
   type SseFinalized,
@@ -192,343 +191,29 @@ describe('sse-schemas', () => {
   });
   });
 
 
   describe('SseFinalizedSchema', () => {
   describe('SseFinalizedSchema', () => {
-    test('should validate minimal finalized response', () => {
+    test('should validate finalized response with success true', () => {
       const validFinalized = {
       const validFinalized = {
-        finalized: {
-          message: 'Changes have been applied successfully.',
-          replacements: [],
-        },
+        success: true,
       };
       };
 
 
       const result = SseFinalizedSchema.safeParse(validFinalized);
       const result = SseFinalizedSchema.safeParse(validFinalized);
       expect(result.success).toBe(true);
       expect(result.success).toBe(true);
       if (result.success) {
       if (result.success) {
-        expect(result.data.finalized.message).toBe(validFinalized.finalized.message);
-        expect(result.data.finalized.replacements).toEqual([]);
-        expect(result.data.finalized.applicationResult).toBeUndefined();
+        expect(result.data.success).toBe(true);
       }
       }
     });
     });
 
 
-    test('should validate finalized response with replacements', () => {
+    test('should validate finalized response with success false', () => {
       const validFinalized = {
       const validFinalized = {
-        finalized: {
-          message: 'Successfully applied 2 changes.',
-          replacements: [
-            {
-              search: 'old code 1',
-              replace: 'new code 1',
-              startLine: 5,
-            },
-            {
-              search: 'old code 2',
-              replace: 'new code 2',
-              startLine: 10,
-              endLine: 12,
-            },
-          ],
-        },
+        success: false,
       };
       };
 
 
       const result = SseFinalizedSchema.safeParse(validFinalized);
       const result = SseFinalizedSchema.safeParse(validFinalized);
       expect(result.success).toBe(true);
       expect(result.success).toBe(true);
       if (result.success) {
       if (result.success) {
-        expect(result.data.finalized.replacements).toHaveLength(2);
-        expect(result.data.finalized.replacements[0].search).toBe('old code 1');
-        expect(result.data.finalized.replacements[1].endLine).toBe(12);
+        expect(result.data.success).toBe(false);
       }
       }
     });
     });
-
-    test('should validate finalized response with successful application result', () => {
-      const validFinalized = {
-        finalized: {
-          message: 'All changes applied successfully.',
-          replacements: [
-            {
-              search: 'test code',
-              replace: 'updated code',
-              startLine: 1,
-            },
-          ],
-          applicationResult: {
-            success: true,
-            appliedCount: 1,
-            totalCount: 1,
-          },
-        },
-      };
-
-      const result = SseFinalizedSchema.safeParse(validFinalized);
-      expect(result.success).toBe(true);
-      if (result.success) {
-        expect(result.data.finalized.applicationResult?.success).toBe(true);
-        expect(result.data.finalized.applicationResult?.appliedCount).toBe(1);
-        expect(result.data.finalized.applicationResult?.totalCount).toBe(1);
-      }
-    });
-
-    test('should validate finalized response with failed application result', () => {
-      const validFinalized = {
-        finalized: {
-          message: 'Some changes failed to apply.',
-          replacements: [],
-          applicationResult: {
-            success: false,
-            appliedCount: 0,
-            totalCount: 1,
-            failedParts: [
-              {
-                type: 'SEARCH_NOT_FOUND',
-                message: 'Could not find the specified search content',
-                line: 10,
-                details: {
-                  searchContent: 'missing code',
-                  bestMatch: 'similar code',
-                  similarity: 0.7,
-                  suggestions: ['Check line numbers', 'Verify content'],
-                  correctFormat: 'function example() {}',
-                  lineRange: '8-12',
-                },
-              },
-            ],
-          },
-        },
-      };
-
-      const result = SseFinalizedSchema.safeParse(validFinalized);
-      expect(result.success).toBe(true);
-      if (result.success) {
-        expect(result.data.finalized.applicationResult?.success).toBe(false);
-        expect(result.data.finalized.applicationResult?.failedParts).toHaveLength(1);
-        expect(result.data.finalized.applicationResult?.failedParts?.[0].type).toBe('SEARCH_NOT_FOUND');
-        expect(result.data.finalized.applicationResult?.failedParts?.[0].details.similarity).toBe(0.7);
-      }
-    });
-
-    test('should validate all error types in failedParts', () => {
-      const errorTypes = [
-        'SEARCH_NOT_FOUND',
-        'SIMILARITY_TOO_LOW',
-        'MULTIPLE_MATCHES',
-        'EMPTY_SEARCH',
-        'MARKER_SEQUENCE_ERROR',
-        'CONTENT_ERROR',
-      ];
-
-      for (const errorType of errorTypes) {
-        const validFinalized = {
-          finalized: {
-            message: `Error type: ${errorType}`,
-            replacements: [],
-            applicationResult: {
-              success: false,
-              appliedCount: 0,
-              totalCount: 1,
-              failedParts: [
-                {
-                  type: errorType,
-                  message: `Test message for ${errorType}`,
-                  details: {
-                    searchContent: 'test',
-                    suggestions: [],
-                  },
-                },
-              ],
-            },
-          },
-        };
-
-        const result = SseFinalizedSchema.safeParse(validFinalized);
-        expect(result.success).toBe(true);
-        if (result.success) {
-          expect(result.data.finalized.applicationResult?.failedParts?.[0].type).toBe(errorType);
-        }
-      }
-    });
-
-    test('should fail when finalized field is missing', () => {
-      const invalidFinalized = {};
-
-      const result = SseFinalizedSchema.safeParse(invalidFinalized);
-      expect(result.success).toBe(false);
-      if (!result.success) {
-        expect(result.error.issues[0].code).toBe('invalid_type');
-        expect(result.error.issues[0].path).toEqual(['finalized']);
-      }
-    });
-
-    test('should fail when message is missing', () => {
-      const invalidFinalized = {
-        finalized: {
-          replacements: [],
-        },
-      };
-
-      const result = SseFinalizedSchema.safeParse(invalidFinalized);
-      expect(result.success).toBe(false);
-      if (!result.success) {
-        const messageError = result.error.issues.find(issue => issue.path.includes('message'));
-        expect(messageError).toBeDefined();
-      }
-    });
-
-    test('should fail when replacements is missing', () => {
-      const invalidFinalized = {
-        finalized: {
-          message: 'Test message',
-        },
-      };
-
-      const result = SseFinalizedSchema.safeParse(invalidFinalized);
-      expect(result.success).toBe(false);
-      if (!result.success) {
-        const replacementsError = result.error.issues.find(issue => issue.path.includes('replacements'));
-        expect(replacementsError).toBeDefined();
-      }
-    });
-
-    test('should fail when appliedCount is negative', () => {
-      const invalidFinalized = {
-        finalized: {
-          message: 'Test',
-          replacements: [],
-          applicationResult: {
-            success: false,
-            appliedCount: -1,
-            totalCount: 1,
-          },
-        },
-      };
-
-      const result = SseFinalizedSchema.safeParse(invalidFinalized);
-      expect(result.success).toBe(false);
-    });
-
-    test('should fail when totalCount is negative', () => {
-      const invalidFinalized = {
-        finalized: {
-          message: 'Test',
-          replacements: [],
-          applicationResult: {
-            success: false,
-            appliedCount: 0,
-            totalCount: -1,
-          },
-        },
-      };
-
-      const result = SseFinalizedSchema.safeParse(invalidFinalized);
-      expect(result.success).toBe(false);
-    });
-
-    test('should fail when similarity is out of range', () => {
-      const invalidFinalized = {
-        finalized: {
-          message: 'Test',
-          replacements: [],
-          applicationResult: {
-            success: false,
-            appliedCount: 0,
-            totalCount: 1,
-            failedParts: [
-              {
-                type: 'SIMILARITY_TOO_LOW',
-                message: 'Low similarity',
-                details: {
-                  searchContent: 'test',
-                  similarity: 1.5, // Invalid: > 1.0
-                  suggestions: [],
-                },
-              },
-            ],
-          },
-        },
-      };
-
-      const result = SseFinalizedSchema.safeParse(invalidFinalized);
-      expect(result.success).toBe(false);
-    });
-
-    test('should fail when line number is not positive', () => {
-      const invalidFinalized = {
-        finalized: {
-          message: 'Test',
-          replacements: [],
-          applicationResult: {
-            success: false,
-            appliedCount: 0,
-            totalCount: 1,
-            failedParts: [
-              {
-                type: 'SEARCH_NOT_FOUND',
-                message: 'Not found',
-                line: 0, // Invalid: must be positive
-                details: {
-                  searchContent: 'test',
-                  suggestions: [],
-                },
-              },
-            ],
-          },
-        },
-      };
-
-      const result = SseFinalizedSchema.safeParse(invalidFinalized);
-      expect(result.success).toBe(false);
-    });
-
-    test('should allow extra fields in finalized', () => {
-      const validFinalized = {
-        finalized: {
-          message: 'Test',
-          replacements: [],
-        },
-        extraField: 'ignored',
-      };
-
-      const result = SseFinalizedSchema.safeParse(validFinalized);
-      expect(result.success).toBe(true);
-    });
-  });
-
-  describe('hasApplicationResult helper', () => {
-    test('should return true when applicationResult is present', () => {
-      const finalized: SseFinalized = {
-        finalized: {
-          message: 'Test',
-          replacements: [],
-          applicationResult: {
-            success: true,
-            appliedCount: 1,
-            totalCount: 1,
-          },
-        },
-      };
-
-      expect(hasApplicationResult(finalized)).toBe(true);
-    });
-
-    test('should return false when applicationResult is undefined', () => {
-      const finalized: SseFinalized = {
-        finalized: {
-          message: 'Test',
-          replacements: [],
-        },
-      };
-
-      expect(hasApplicationResult(finalized)).toBe(false);
-    });
-
-    test('should return false when applicationResult is undefined (explicit)', () => {
-      const finalized: SseFinalized = {
-        finalized: {
-          message: 'Test',
-          replacements: [],
-          applicationResult: undefined,
-        },
-      };
-
-      expect(hasApplicationResult(finalized)).toBe(false);
-    });
   });
   });
 
 
   describe('Type inference', () => {
   describe('Type inference', () => {
@@ -556,77 +241,11 @@ describe('sse-schemas', () => {
 
 
     test('SseFinalized type should match schema', () => {
     test('SseFinalized type should match schema', () => {
       const finalized: SseFinalized = {
       const finalized: SseFinalized = {
-        finalized: {
-          message: 'Done',
-          replacements: [],
-        },
+        success: true,
       };
       };
 
 
       const result = SseFinalizedSchema.safeParse(finalized);
       const result = SseFinalizedSchema.safeParse(finalized);
       expect(result.success).toBe(true);
       expect(result.success).toBe(true);
     });
     });
   });
   });
-
-  describe('Real-world scenarios', () => {
-    test('should validate complete SSE flow', () => {
-      const realWorldFinalized = {
-        finalized: {
-          message: 'Successfully refactored the authentication function and added error handling.',
-          replacements: [
-            {
-              search: 'function authenticate(token) {\n  return validateToken(token);\n}',
-              // eslint-disable-next-line max-len
-              replace: 'async function authenticate(token) {\n  try {\n    if (!token) {\n      throw new Error("Token is required");\n    }\n    return await validateToken(token);\n  } catch (error) {\n    console.error("Authentication failed:", error);\n    throw error;\n  }\n}',
-              startLine: 25,
-              endLine: 27,
-            },
-          ],
-          applicationResult: {
-            success: true,
-            appliedCount: 1,
-            totalCount: 1,
-          },
-        },
-      };
-
-      const result = SseFinalizedSchema.safeParse(realWorldFinalized);
-      expect(result.success).toBe(true);
-    });
-
-    test('should validate error scenario with detailed feedback', () => {
-      const errorScenario = {
-        finalized: {
-          message: 'Failed to apply changes. The specified code was not found.',
-          replacements: [],
-          applicationResult: {
-            success: false,
-            appliedCount: 0,
-            totalCount: 1,
-            failedParts: [
-              {
-                type: 'SEARCH_NOT_FOUND',
-                message: 'Could not find exact match for the specified code',
-                line: 25,
-                details: {
-                  searchContent: 'function authenticate(token) {',
-                  bestMatch: 'function authenticateUser(userToken) {',
-                  similarity: 0.85,
-                  suggestions: [
-                    'Check if the function name has changed',
-                    'Verify the parameter name is correct',
-                    'Ensure the code structure matches exactly',
-                  ],
-                  correctFormat: 'function authenticateUser(userToken) {',
-                  lineRange: '20-30',
-                },
-              },
-            ],
-          },
-        },
-      };
-
-      const result = SseFinalizedSchema.safeParse(errorScenario);
-      expect(result.success).toBe(true);
-    });
-  });
 });
 });

+ 2 - 37
apps/app/src/features/openai/interfaces/editor-assistant/sse-schemas.ts

@@ -15,47 +15,12 @@ export const SseDetectedDiffSchema = z.object({
   diff: LlmEditorAssistantDiffSchema,
   diff: LlmEditorAssistantDiffSchema,
 });
 });
 
 
-// Enhanced finalized schema with detailed application results
+// Simplified finalized schema
 export const SseFinalizedSchema = z.object({
 export const SseFinalizedSchema = z.object({
-  finalized: z.object({
-    message: z.string()
-      .describe('The final message that should be displayed in the chat window'),
-    replacements: z.array(LlmEditorAssistantDiffSchema),
-    // Enhanced error reporting from multi-search-replace processor
-    applicationResult: z.object({
-      success: z.boolean(),
-      appliedCount: z.number().int().min(0),
-      totalCount: z.number().int().min(0),
-      failedParts: z.array(z.object({
-        type: z.enum([
-          'SEARCH_NOT_FOUND',
-          'SIMILARITY_TOO_LOW',
-          'MULTIPLE_MATCHES',
-          'EMPTY_SEARCH',
-          'MARKER_SEQUENCE_ERROR',
-          'CONTENT_ERROR',
-        ]),
-        message: z.string(),
-        line: z.number().int().positive().optional(),
-        details: z.object({
-          searchContent: z.string(),
-          bestMatch: z.string().optional(),
-          similarity: z.number().min(0).max(1).optional(),
-          suggestions: z.array(z.string()),
-          correctFormat: z.string().optional(),
-          lineRange: z.string().optional(),
-        }),
-      })).optional(),
-    }).optional(),
-  }),
+  success: z.boolean(),
 });
 });
 
 
 // Type definitions
 // Type definitions
 export type SseMessage = z.infer<typeof SseMessageSchema>;
 export type SseMessage = z.infer<typeof SseMessageSchema>;
 export type SseDetectedDiff = z.infer<typeof SseDetectedDiffSchema>;
 export type SseDetectedDiff = z.infer<typeof SseDetectedDiffSchema>;
 export type SseFinalized = z.infer<typeof SseFinalizedSchema>;
 export type SseFinalized = z.infer<typeof SseFinalizedSchema>;
-
-// Helper functions for response type checking
-export const hasApplicationResult = (finalized: SseFinalized): boolean => {
-  return finalized.finalized.applicationResult !== undefined;
-};

+ 2 - 1
apps/app/src/features/openai/server/routes/edit/index.ts

@@ -205,8 +205,9 @@ export const postMessageToEditHandlersFactory: PostMessageHandlersFactory = (cro
         diffDetectedCallback: (detected) => {
         diffDetectedCallback: (detected) => {
           sseHelper.writeData<SseDetectedDiff>({ diff: detected });
           sseHelper.writeData<SseDetectedDiff>({ diff: detected });
         },
         },
+        // eslint-disable-next-line @typescript-eslint/no-unused-vars
         dataFinalizedCallback: (message, replacements) => {
         dataFinalizedCallback: (message, replacements) => {
-          sseHelper.writeData<SseFinalized>({ finalized: { message: message ?? '', replacements } });
+          sseHelper.writeData<SseFinalized>({ success: true });
         },
         },
       });
       });